OpenClonk
C4GameOptions.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, 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 // Custom game options and configuration dialog
17 
18 #include "C4Include.h"
19 #include "gui/C4GameOptions.h"
20 
21 #include "control/C4GameControl.h"
22 #include "game/C4Application.h"
24 #include "gui/C4GameLobby.h"
25 #include "gui/C4Startup.h"
26 
27 // ----------- C4GameOptionsList::Option ----------------------------------------------------------------
28 
29 C4GameOptionsList::Option::Option(C4GameOptionsList *pForDlg) :
30  BaseClass(C4Rect(0, 0, 0, 0)), pForDlg(pForDlg), pPrimarySubcomponent(nullptr)
31 {}
32 
33 void C4GameOptionsList::Option::InitOption(C4GameOptionsList *pForDlg)
34 {
35  // post-call after initialization: Adds to list box and does initial update
36  // add to listbox (will eventually get moved)
37  pForDlg->AddElement(this);
38  // first-time update
39  Update();
40 }
41 
42 
43 
44 // ----------- C4GameOptionsList::OptionDropdown ----------------------------------------------------------------
45 
46 C4GameOptionsList::OptionDropdown::OptionDropdown(class C4GameOptionsList *pForDlg, const char *szCaption, bool fReadOnly)
47  : Option(pForDlg), fReadOnly(fReadOnly)
48 {
49  bool fIsPreGame = pForDlg->IsPreGame();
51  uint32_t dwFontClr = fIsPreGame ? C4StartupFontClr : 0xffffffff;
52  // get size of caption label
53  bool fTabular = pForDlg->IsTabular();
54  int32_t iCaptWidth, iCaptHeight;
55  if (fTabular)
56  {
57  // tabular layout: Caption label width by largest caption on runtime; fixed 1/3rd on startup
58  rUseFont.GetTextExtent(LoadResStr("IDS_NET_RUNTIMEJOIN"), iCaptWidth, iCaptHeight, true);
59  if (pForDlg->IsPreGame())
60  {
61  iCaptWidth = pForDlg->GetItemWidth() * 1 / 3;
62  }
63  else
64  {
65  iCaptWidth = iCaptWidth * 5 / 4;
66  }
67  }
68  else
69  {
70  rUseFont.GetTextExtent(szCaption, iCaptWidth, iCaptHeight, true);
71  }
72  // calc total height for component
73  int iHorizontalMargin = 1;
74  int iVerticalMargin = 1;
75  int iComboMargin = 5;
76  int iSelComboHgt = C4GUI::ComboBox::GetDefaultHeight();
77  SetBounds(C4Rect(0, 0, pForDlg->GetItemWidth(), (!fTabular) * (iCaptHeight + iVerticalMargin*2) + iVerticalMargin*2 + iSelComboHgt));
78  C4GUI::ComponentAligner ca(GetContainedClientRect(), iHorizontalMargin, iVerticalMargin);
79  // create subcomponents
80  AddElement(pCaption = new C4GUI::Label(FormatString("%s:", szCaption).getData(), fTabular ? ca.GetFromLeft(iCaptWidth, iCaptHeight) : ca.GetFromTop(iCaptHeight), ALeft, dwFontClr, &rUseFont, false, false));
81  ca.ExpandLeft(-iComboMargin);
82  AddElement(pPrimarySubcomponent = pDropdownList = new C4GUI::ComboBox(ca.GetAll()));
83  pDropdownList->SetReadOnly(fReadOnly);
84  pDropdownList->SetComboCB(new C4GUI::ComboBox_FillCallback<C4GameOptionsList::OptionDropdown>(this, &C4GameOptionsList::OptionDropdown::OnDropdownFill, &C4GameOptionsList::OptionDropdown::OnDropdownSelChange));
85  if (fIsPreGame)
86  {
88  pDropdownList->SetFont(&rUseFont);
89  pDropdownList->SetDecoration(&(C4Startup::Get()->Graphics.fctContext));
90  }
91  // final init
92  InitOption(pForDlg);
93 }
94 
95 
96 
97 // ----------- C4GameOptionsList::OptionScenarioParameter----------------------------------------------------------------
98 
99 C4GameOptionsList::OptionScenarioParameter::OptionScenarioParameter(class C4GameOptionsList *pForDlg, const class C4ScenarioParameterDef *parameter_def)
100  : C4GameOptionsList::OptionDropdown(pForDlg, parameter_def->GetName(), !pForDlg->IsPreGame() && (!::Control.isCtrlHost() || ::Game.C4S.Head.SaveGame)), ParameterDef(parameter_def), LastValue(0), LastValueValid(false)
101 {
102  SetToolTip(parameter_def->GetDescription());
103 }
104 
105 void C4GameOptionsList::OptionScenarioParameter::DoDropdownFill(C4GUI::ComboBox_FillCB *pFiller)
106 {
107  // Fill dropdown menuy with known possible options for this parameter
108  size_t idx=0; const C4ScenarioParameterDef::Option *option;
109  while ((option = ParameterDef->GetOptionByIndex(idx++)))
110  {
111  pFiller->AddEntry(option->Name.getData(), option->Value);
112  }
113 }
114 
115 void C4GameOptionsList::OptionScenarioParameter::DoDropdownSelChange(int32_t idNewSelection)
116 {
117  // runtime change needs to be synchronized
118  if (!pForDlg->IsPreGame())
119  {
120  // change possible?
121  if (!::Control.isCtrlHost()) return;
122  // Then initiate an update of the parameters on all clients
123  C4GameLobby::C4PacketSetScenarioParameter pck(ParameterDef->GetID(), idNewSelection);
125  }
126  // also process on host (and standalone pre-game)
127  pForDlg->GetParameters()->SetValue(ParameterDef->GetID(), idNewSelection, false);
128  if (pForDlg->IsPreGame()) Update();
129 }
130 
131 void C4GameOptionsList::OptionScenarioParameter::Update()
132 {
133  int32_t val=0;
134  // display forced league value?
135  bool fLeagueReadOnly = false;
136  if (::Config.Network.LeagueServerSignUp && !fReadOnly && !pForDlg->IsPreGameSingle()) val = ParameterDef->GetLeagueValue();
137  if (val)
138  fLeagueReadOnly = true;
139  else
140  val = pForDlg->GetParameters()->GetValueByID(ParameterDef->GetID(), ParameterDef->GetDefault());
141  if (!fReadOnly) pDropdownList->SetReadOnly(fLeagueReadOnly);
142  // update data to currently set option
143  if (LastValueValid && val == LastValue) return;
144  const C4ScenarioParameterDef::Option *option = ParameterDef->GetOptionByValue(val);
145  if (option)
146  pDropdownList->SetText(option->Name.getData());
147  else
148  pDropdownList->SetText(FormatString("%d", (int)val).getData());
149  LastValueValid = true;
150  LastValue = val;
151 }
152 
153 
154 
155 // ----------- C4GameOptionsList::OptionControlMode ----------------------------------------------------------------
156 
157 // Unfortunately, the control mode cannot be changed in the lobby
158 C4GameOptionsList::OptionControlMode::OptionControlMode(class C4GameOptionsList *pForDlg)
159  : C4GameOptionsList::OptionDropdown(pForDlg, LoadResStr("IDS_TEXT_CONTROLMODE"), !::Control.isCtrlHost() || !::Control.isNetwork() || !::Control.Network.IsEnabled())
160 {
161  SetToolTip(LoadResStr("IDS_DESC_CHANGESTHEWAYCONTROLDATAI"));
162 }
163 
164 void C4GameOptionsList::OptionControlMode::DoDropdownFill(C4GUI::ComboBox_FillCB *pFiller)
165 {
166  // change possible?
167  if (!::Control.isNetwork() || !::Control.Network.IsEnabled() || !::Control.isCtrlHost()) return;
168  // add possible modes
169  pFiller->AddEntry(LoadResStr("IDS_NET_CTRLMODE_CENTRAL"), CNM_Central);
170  pFiller->AddEntry(LoadResStr("IDS_NET_CTRLMODE_DECENTRAL"), CNM_Decentral);
171 }
172 
173 void C4GameOptionsList::OptionControlMode::DoDropdownSelChange(int32_t idNewSelection)
174 {
175  // change possible?
176  if (!::Control.isNetwork() || !::Control.Network.IsEnabled() || !::Control.isCtrlHost()) return;
177  // perform it
178  ::Network.SetCtrlMode(idNewSelection);
179  // update for clients done by packet; host needs to set it manually
180  Update();
181 }
182 
183 void C4GameOptionsList::OptionControlMode::Update()
184 {
185  const char *szControlMode;
186  if (!::Control.isNetwork() || !::Control.Network.IsEnabled())
187  szControlMode = LoadResStr("IDS_NET_NONET");
188  else
189  {
190  switch (::Network.Status.getCtrlMode())
191  {
192  case CNM_Central: szControlMode = LoadResStr("IDS_NET_CTRLMODE_CENTRAL"); break;
193  case CNM_Decentral: szControlMode = LoadResStr("IDS_NET_CTRLMODE_DECENTRAL"); break;
194  default: szControlMode = LoadResStr("IDS_NET_CTRLMODE_NONE"); break;
195  }
196  }
197  pDropdownList->SetText(szControlMode);
198 }
199 
200 
201 // ----------- C4GameOptionsList::OptionControlRate ----------------------------------------------------------------
202 
203 C4GameOptionsList::OptionControlRate::OptionControlRate(class C4GameOptionsList *pForDlg)
204  : C4GameOptionsList::OptionDropdown(pForDlg, LoadResStr("IDS_CTL_CONTROLRATE"), !::Control.isCtrlHost())
205 {
206  SetToolTip(LoadResStr("IDS_CTL_CONTROLRATE_DESC"));
207 }
208 
209 void C4GameOptionsList::OptionControlRate::DoDropdownFill(C4GUI::ComboBox_FillCB *pFiller)
210 {
211  for (int i = 1; i < std::min(C4MaxControlRate, 10); ++i)
212  pFiller->AddEntry(FormatString("%d", i).getData(), i);
213 }
214 
215 void C4GameOptionsList::OptionControlRate::DoDropdownSelChange(int32_t idNewSelection)
216 {
217  // adjust rate
218  int32_t iNewRate = idNewSelection;
219  if (!iNewRate || iNewRate == ::Control.ControlRate) return;
221 }
222 
223 void C4GameOptionsList::OptionControlRate::Update()
224 {
225  if (atoi(pDropdownList->GetText().getData()) == ::Control.ControlRate) return;
226  pDropdownList->SetText(FormatString("%d", ::Control.ControlRate).getData());
227 }
228 
229 
230 // ----------- C4GameOptionsList::OptionRuntimeJoin ----------------------------------------------------------------
231 
232 C4GameOptionsList::OptionRuntimeJoin::OptionRuntimeJoin(class C4GameOptionsList *pForDlg)
233  : C4GameOptionsList::OptionDropdown(pForDlg, LoadResStr("IDS_NET_RUNTIMEJOIN"), !::Network.isHost())
234 {
235  SetToolTip(LoadResStr("IDS_NET_RUNTIMEJOIN_DESC"));
236 }
237 
238 void C4GameOptionsList::OptionRuntimeJoin::DoDropdownFill(C4GUI::ComboBox_FillCB *pFiller)
239 {
240  pFiller->AddEntry(LoadResStr("IDS_NET_RUNTIMEJOINBARRED"), 0);
241  pFiller->AddEntry(LoadResStr("IDS_NET_RUNTIMEJOINFREE"), 1);
242 }
243 
244 void C4GameOptionsList::OptionRuntimeJoin::DoDropdownSelChange(int32_t idNewSelection)
245 {
246  // adjust mode
247  bool fAllowed = !!idNewSelection;
248  Config.Network.NoRuntimeJoin = !fAllowed;
249  if (Game.IsRunning) ::Network.AllowJoin(fAllowed);
250 }
251 
252 void C4GameOptionsList::OptionRuntimeJoin::Update()
253 {
254  const char *szText;
256  szText = LoadResStr("IDS_NET_RUNTIMEJOINBARRED");
257  else
258  szText = LoadResStr("IDS_NET_RUNTIMEJOINFREE");
259  pDropdownList->SetText(szText);
260 }
261 
262 
263 // ----------- C4GameOptionsList::OptionTeamDist ----------------------------------------------------------------
264 
265 C4GameOptionsList::OptionTeamDist::OptionTeamDist(class C4GameOptionsList *pForDlg)
266  : C4GameOptionsList::OptionDropdown(pForDlg, LoadResStr("IDS_MSG_TEAMDIST"), !::Control.isCtrlHost())
267 {
268  SetToolTip(LoadResStr("IDS_MSG_TEAMDIST_DESC"));
269 }
270 
271 void C4GameOptionsList::OptionTeamDist::DoDropdownFill(C4GUI::ComboBox_FillCB *pFiller)
272 {
273  Game.Teams.FillTeamDistOptions(pFiller);
274 }
275 
276 void C4GameOptionsList::OptionTeamDist::DoDropdownSelChange(int32_t idNewSelection)
277 {
278  // adjust team distribution
280 }
281 
282 void C4GameOptionsList::OptionTeamDist::Update()
283 {
284  StdStrBuf sOption; sOption.Take(Game.Teams.GetTeamDistString());
285  pDropdownList->SetText(sOption.getData());
286 }
287 
288 
289 // ----------- C4GameOptionsList::OptionTeamColors ----------------------------------------------------------------
290 
291 C4GameOptionsList::OptionTeamColors::OptionTeamColors(class C4GameOptionsList *pForDlg)
292  : C4GameOptionsList::OptionDropdown(pForDlg, LoadResStr("IDS_MSG_TEAMCOLORS"), !::Control.isCtrlHost())
293 {
294  SetToolTip(LoadResStr("IDS_MSG_TEAMCOLORS_DESC"));
295 }
296 
297 void C4GameOptionsList::OptionTeamColors::DoDropdownFill(C4GUI::ComboBox_FillCB *pFiller)
298 {
299  pFiller->AddEntry(LoadResStr("IDS_MSG_ENABLED"), 1);
300  pFiller->AddEntry(LoadResStr("IDS_MSG_DISABLED"), 0);
301 }
302 
303 void C4GameOptionsList::OptionTeamColors::DoDropdownSelChange(int32_t idNewSelection)
304 {
305  bool fEnabled = !!idNewSelection;
306  Game.Teams.SendSetTeamColors(fEnabled);
307 }
308 
309 void C4GameOptionsList::OptionTeamColors::Update()
310 {
311  pDropdownList->SetText(Game.Teams.IsTeamColors() ? LoadResStr("IDS_MSG_ENABLED") : LoadResStr("IDS_MSG_DISABLED"));
312 }
313 
314 // ----------- C4GameOptionsList -----------------------------------------------------------------------
315 
317  : C4GUI::ListBox(rcBounds), source(source), param_defs(param_defs), params(params)
318 {
319  // default parameter defs
320  if (!IsPreGame())
321  {
322  if (!this->param_defs) this->param_defs = &::Game.ScenarioParameterDefs;
323  if (!this->params) this->params = &::Game.Parameters.ScenarioParameters;
324  }
325  // initial option fill
326  InitOptions();
327  if (fActive) Activate();
328 }
329 
330 void C4GameOptionsList::InitOptions()
331 {
332  // create options for custom scenario parameters
333  if (param_defs)
334  {
335  size_t idx = 0; const C4ScenarioParameterDef *def;
336  while ((def = param_defs->GetParameterDefByIndex(idx++)))
337  if (!def->IsAchievement()) // achievements are displayed in scenario selection. no need to repeat them here
338  new OptionScenarioParameter(this, def);
339  }
340  // create lobby and runtime option selection components
341  if (!IsPreGame())
342  {
343  new OptionControlMode(this);
344  new OptionControlRate(this);
345  if (::Network.isHost()) new OptionRuntimeJoin(this);
346  if (!IsRuntime())
347  {
348  if (Game.Teams.HasTeamDistOptions()) new OptionTeamDist(this);
349  if (Game.Teams.IsMultiTeams()) new OptionTeamColors(this);
350  }
351  }
352 }
353 
354 void C4GameOptionsList::ClearOptions()
355 {
357  while ((pFirst = GetFirst())) delete pFirst;
358 }
359 
361 {
362  // update all option items
363  for (Option *pItem = static_cast<Option *>(pClientWindow->GetFirst()); pItem; pItem = pItem->GetNext())
364  pItem->Update();
365 }
366 
368 {
369  // register timer if necessary
370  Application.Add(this);
371  // force an update
372  Update();
373 }
374 
376 {
377  // release timer if set
378  Application.Remove(this);
379 }
380 
382 {
383  // update to new parameter set
384  ClearOptions();
385  this->param_defs = param_defs;
386  this->params = params;
387  InitOptions();
388 }
389 
C4Config Config
Definition: C4Config.cpp:930
const int C4MaxControlRate
Definition: C4Constants.h:33
C4GameControl Control
@ CNM_Decentral
@ CNM_Central
C4Game Game
Definition: C4Globals.cpp:52
C4Application Application
Definition: C4Globals.cpp:44
C4Network2 Network
Definition: C4Globals.cpp:53
C4GraphicsResource GraphicsResource
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
C4NetIOPacket MkC4NetIOPacket(char cStatus, const class C4PacketBase &Pkt, const C4NetIO::addr_t &addr=C4NetIO::addr_t())
Definition: C4PacketBase.h:40
@ PID_SetScenarioParameter
Definition: C4PacketBase.h:126
const int32_t C4StartupEditBorderColor
Definition: C4Startup.h:30
const int32_t C4StartupEditBGColor
Definition: C4Startup.h:29
const int32_t C4StartupFontClr
Definition: C4Startup.h:27
const int ALeft
Definition: C4Surface.h:41
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
C4ConfigNetwork Network
Definition: C4Config.h:259
int32_t LeagueServerSignUp
Definition: C4Config.h:151
int32_t NoRuntimeJoin
Definition: C4Config.h:142
void AddEntry(const char *szText, int32_t id)
static int32_t GetDefaultHeight()
Element * pFirst
Definition: C4Gui.h:750
Element * GetFirst()
Definition: C4Gui.h:829
bool AddElement(Element *pChild, int32_t iIndent=0)
Element * GetFirst()
Definition: C4Gui.h:1572
ScrollWindow * pClientWindow
Definition: C4Gui.h:1510
int32_t GetItemWidth()
Definition: C4Gui.h:1546
int32_t ControlRate
Definition: C4GameControl.h:88
C4GameControlNetwork Network
Definition: C4GameControl.h:67
void AdjustControlRate(int32_t iBy)
bool isCtrlHost() const
Definition: C4GameControl.h:99
bool isNetwork() const
Definition: C4GameControl.h:97
C4TeamList & Teams
Definition: C4Game.h:70
bool IsRunning
Definition: C4Game.h:140
class C4ScenarioParameterDefs & ScenarioParameterDefs
Definition: C4Game.h:75
C4GameParameters & Parameters
Definition: C4Game.h:67
bool IsPreGame() const
bool IsPreGameSingle() const
bool IsRuntime() const
C4ScenarioParameters * GetParameters()
bool IsTabular() const
void SetParameters(C4ScenarioParameterDefs *param_defs, C4ScenarioParameters *params)
C4GameOptionsList(const C4Rect &rcBounds, bool fActive, C4GameOptionsListSource source, class C4ScenarioParameterDefs *param_defs=nullptr, class C4ScenarioParameters *params=nullptr)
C4ScenarioParameters ScenarioParameters
bool BroadcastMsgToClients(const C4NetIOPacket &rPkt)
C4Network2Status Status
Definition: C4Network2.h:122
void AllowJoin(bool fAllow)
Definition: C4Network2.cpp:802
bool isHost() const
Definition: C4Network2.h:209
void SetCtrlMode(int32_t iCtrlMode)
Definition: C4Network2.cpp:819
C4Network2ClientList Clients
Definition: C4Network2.h:116
int32_t getCtrlMode() const
Definition: C4Network2.h:81
Definition: C4Rect.h:28
const char * GetDescription() const
const C4ScenarioParameterDef * GetParameterDefByIndex(size_t idx) const
int32_t GetValueByID(const char *id, int32_t default_value) const
void SetValue(const char *id, int32_t value, bool only_if_larger)
CStdFont BookFont
Definition: C4Startup.h:77
static C4Startup * Get()
Definition: C4Startup.h:147
C4StartupGraphics Graphics
Definition: C4Startup.h:112
bool IsMultiTeams() const
Definition: C4Teams.h:162
bool IsTeamColors() const
Definition: C4Teams.h:169
void FillTeamDistOptions(C4GUI::ComboBox_FillCB *pFiller) const
Definition: C4Teams.cpp:778
StdStrBuf GetTeamDistString() const
Definition: C4Teams.cpp:797
void SendSetTeamDist(TeamDist eNewDist)
Definition: C4Teams.cpp:790
void SendSetTeamColors(bool fEnabled)
Definition: C4Teams.cpp:833
bool HasTeamDistOptions() const
Definition: C4Teams.cpp:803
bool GetTextExtent(const char *szText, int32_t &rsx, int32_t &rsy, bool fCheckMarkup=true)
void Remove(StdSchedulerProc *pProc)
void Add(StdSchedulerProc *pProc)
const char * getData() const
Definition: StdBuf.h:442
void Take(char *pnData)
Definition: StdBuf.h:457