1 #include "pch.h"
2 #include "common/Def_Str.h"
3 #include "common/Gui_Def.h"
4 #include "common/data/CData.h"
5 #include "common/data/BltObjects.h"
6 #include "common/CScene.h"
7 #include "../vdrift/pathmanager.h"
8 #include "../vdrift/game.h"
9 #include "CGui.h"
10 #include "CGame.h"
11 #include "CarModel.h"
12 #include <MyGUI_Window.h>
13 #include <MyGUI_InputManager.h>
14 #include <MyGUI_TabControl.h>
15 #include <MyGUI_TabItem.h>
16 #include <MyGUI_EditBox.h>
17 #include <MyGUI_TextBox.h>
18 #include <MyGUI_ComboBox.h>
19 #include <boost/filesystem.hpp>
20 using namespace std;
21 using namespace Ogre;
22 using namespace MyGUI;
23 namespace fs = boost::filesystem;
24
25
26 /// Tweak Car
27 //-----------------------------------------------------------------------------------------------------------
28
TweakCarSave()29 void CGui::TweakCarSave()
30 {
31 String text = "";
32 for (int i=0; i < ciEdCar; ++i) // sum all edits
33 text += edCar[i]->getCaption();
34 if (text == "") return;
35
36 text = StringUtil::replaceAll(text, "##", "#");
37 text = StringUtil::replaceAll(text, "#E5F4FF", ""); //!
38
39 std::string path, pathUser, pathUserDir;
40 bool user = GetCarPath(&path, &pathUser, &pathUserDir, pSet->game.car[0]);
41
42 PATHMANAGER::CreateDir(pathUserDir);
43 std::ofstream fo(pathUser.c_str());
44 fo << text.c_str();
45 fo.close();
46
47 app->NewGame();
48 }
49
50 // fill gui with .car sections
TweakCarLoad()51 void CGui::TweakCarLoad()
52 {
53 std::string path, pathUser, pathUserDir;
54 bool user = GetCarPath(&path, &pathUser, &pathUserDir, pSet->game.car[0]);
55
56 if (!PATHMANAGER::FileExists(path))
57 {
58 for (int i=0; i < ciEdCar; ++i)
59 edCar[i]->setCaption("");
60 txtTweakPath->setCaption("Not Found ! " + path);
61 txtTweakPath->setColour(Colour(1,0,0));
62 }else
63 {
64 std::ifstream fi(path.c_str());
65 const int iSecNum = 11;
66 const static String sSecNames[iSecNum] = {
67 "collision", "engine", "transmission", "suspension",
68 "tire", "brakes", " drag", "wheel-F", "wheel-R", "particle-0", "aaa"};
69
70 String s; std::vector<String> lines;
71 int secLn[ciEdCar];
72 for (int i=0; i < ciEdCar; ++i) secLn[i]=0;
73
74 int l=0, sec=0, sec0=0, lastEmp = 0;
75 while (getline(fi,s))
76 {
77 s += "\n";
78 s = StringUtil::replaceAll(s, "#", "##");
79 s = StringUtil::replaceAll(s, "#E5F4FF", ""); //clr!-
80
81 // split to car edit sections
82 bool emp = s == "\n";
83 if (emp) { lastEmp = l; secLn[sec] = l; }
84
85 // check section name
86 bool found = false; int sn=sec0;
87 if (!emp && s[0] == '[')
88 while (!found && sn < iSecNum)
89 {
90 if (sn == 1 && s.find("hover") != std::string::npos)
91 { found = true; ++sec; ++sec0; }
92 else
93 if (sn == 2 && s.find("hover_h") != std::string::npos)
94 { found = true; ++sec; ++sec0; }
95 else
96 if (s.find(sSecNames[sn]) != std::string::npos)
97 { found = true; ++sec; ++sec0; }
98 ++sn;
99 }
100 if (s.find("torque-val-mul") != std::string::npos)
101 {
102 lastEmp = l; secLn[sec] = l; ++sec;
103 }
104
105 lines.push_back(s); ++l;
106 }
107 fi.close();
108
109 for (int i=0; i < ciEdCar; ++i)
110 edCar[i]->setCaption("");
111
112 sec = 0; s = "";
113 for (l=0; l < lines.size(); ++l)
114 {
115 //s += lines[l];
116 // next sec or last line
117 if (l==lines.size()-1 || l >= secLn[sec])
118 {
119 //edCar[sec]->setCaption(edCar[sec]->getCaption() + UString(s));
120 //s="";
121 if (sec < ciEdCar-1) ++sec;
122 }
123 edCar[sec]->setCaption(edCar[sec]->getCaption() + UString(lines[l]));
124 }
125
126 //edTweak->setCaption(UString(text));
127 //edCar[sec]->getVScrollPosition(0);
128 //void setTextCursor(size_t _index);
129 /** Get text cursor position */
130 //size_t getTextCursor() const;
131
132 size_t p = path.find("carsim");
133 if (p != string::npos)
134 path = path.substr(p+7, path.length());
135 txtTweakPath->setCaption(TR(user ? "#{TweakUser}: " : "#{TweakOriginal}: ") + path);
136 txtTweakPath->setTextColour(user ? Colour(1,1,0.5) : Colour(0.5,1,1));
137
138 //MyGUI::InputManager::getInstance().resetKeyFocusWidget();
139 //MyGUI::InputManager::getInstance().setKeyFocusWidget(edTweak);
140 }
141 }
142
143
144 // buttons, events
145 //-----------------------------------------------------------------------------------------------------------
146
btnTweakCarSave(WP)147 void CGui::btnTweakCarSave(WP){ TweakCarSave(); }
btnTweakCarLoad(WP)148 void CGui::btnTweakCarLoad(WP){ TweakCarLoad(); }
btnTweakTireSave(WP)149 void CGui::btnTweakTireSave(WP){ TweakTireSave(); }
150
editTweakTireSet(Ed ed)151 void CGui::editTweakTireSet(Ed ed)
152 {
153 if (txtTweakTire)
154 txtTweakTire->setCaption("");
155 }
156
listTwkTiresUser(Li li,size_t id)157 void CGui::listTwkTiresUser(Li li, size_t id)
158 {
159 if (id==ITEM_NONE || li->getItemCount() == 0) return;
160 pGame->PickTireRef(li->getItemNameAt(id).substr(7));
161 liTwkTiresOrig->setIndexSelected(ITEM_NONE);
162 }
listTwkTiresOrig(Li li,size_t id)163 void CGui::listTwkTiresOrig(Li li, size_t id)
164 {
165 if (id==ITEM_NONE || li->getItemCount() == 0) return;
166 pGame->PickTireRef(li->getItemNameAt(id).substr(7));
167 liTwkTiresUser->setIndexSelected(ITEM_NONE);
168 }
169
btnTweakTireDelete(WP)170 void CGui::btnTweakTireDelete(WP)
171 {
172 if (liTwkTiresUser->getItemCount() == 0) return;
173 size_t id = liTwkTiresUser->getIndexSelected();
174 if (id==ITEM_NONE) return;
175
176 string name = liTwkTiresUser->getItemNameAt(id).substr(7);
177 string path = PATHMANAGER::CarSimU() + "/" + pSet->game.sim_mode + "/tires/" + name + ".tire";
178
179 if (PATHMANAGER::FileExists(path))
180 { fs::remove(path);
181 txtTweakTire->setCaption(TR("#FF8080#{RplDelete}: "+name));
182 pGame->reloadSimNeed = true; // to remove from list
183 }
184 }
185
186 // Load Tire
btnTweakTireLoad(WP)187 void CGui::btnTweakTireLoad(WP)
188 {
189 if (app->carModels.size() < 1) return;
190 CAR* pCar = app->carModels[0]->pCar;
191 if (!pCar) return;
192
193 // load as current, from wheel
194 CARTIRE* tire = pCar->dynamics.GetTire(FRONT_LEFT);
195 if (!tire) return;
196
197 string s, st = tire->name;
198 size_t id = liTwkTiresUser->getIndexSelected();
199 if (id != ITEM_NONE) // user
200 s = liTwkTiresUser->getItemNameAt(id).substr(7);
201 else
202 { id = liTwkTiresOrig->getIndexSelected();
203 if (id != ITEM_NONE)
204 s = liTwkTiresOrig->getItemNameAt(id).substr(7);
205 }
206 if (!s.empty())
207 {
208 int ti = pGame->tires_map[s]-1; if (ti == -1) return;
209 *tire = pGame->tires[ti]; // set pars
210 tire->CalculateSigmaHatAlphaHat();
211
212 if (!sTireLoad.empty())
213 sTireLoad = "";
214 else
215 txtTweakTire->setCaption(TR("#FFFF30#{Loaded}: "+s+" into "+st));
216 return;
217 }
218 }
219
chkTEupd(Ck *)220 void CGui::chkTEupd(Ck*)
221 {
222 chkGraphs(0);
223 }
224
225
FillTweakLists()226 void CGui::FillTweakLists()
227 {
228 // clear
229 liTwkTiresUser->removeAllItems();
230 liTwkTiresOrig->removeAllItems();
231 cmbSurfTire->removeAllItems();
232 liTwkSurfaces->removeAllItems();
233
234 // tires
235 for (int i=0; i < pGame->tires.size(); ++i)
236 {
237 const CARTIRE& ct = pGame->tires[i];
238 if (ct.user)
239 { liTwkTiresUser->addItem("#C0F0F0"+ct.name);
240 if (ct.name == sTireLoad) liTwkTiresUser->setIndexSelected(liTwkTiresUser->getItemCount()-1);
241 }else
242 { liTwkTiresOrig->addItem("#A0D0F0"+ct.name);
243 if (ct.name == sTireLoad) liTwkTiresOrig->setIndexSelected(liTwkTiresUser->getItemCount()-1);
244 }
245 cmbSurfTire->addItem(ct.name);
246 }
247 // surf
248 for (int i=0; i < pGame->surfaces.size(); ++i)
249 {
250 const TRACKSURFACE& su = pGame->surfaces[i];
251 liTwkSurfaces->addItem("#C0C0F0"+su.name);
252 }
253 }
254
255 // Surfaces
256 //-----------------------------------------------------------------------------------------------------------
listTwkSurfaces(Li,size_t id)257 void CGui::listTwkSurfaces(Li, size_t id)
258 {
259 if (id == ITEM_NONE) return;
260 updSld_TwkSurf(id);
261 }
262
btnTwkSurfPick(WP)263 void CGui::btnTwkSurfPick(WP)
264 {
265 if (app->carModels.size() < 1) return;
266 CAR* pCar = app->carModels[0]->pCar;
267 if (!pCar) return;
268
269 CARDYNAMICS& cd = pCar->dynamics;
270 const TRACKSURFACE& tsu = cd.GetWheelContact(FRONT_LEFT).GetSurface();
271 int id=-1; // find in game, not const
272 for (size_t i=0; i < pGame->surfaces.size(); ++i)
273 if (pGame->surfaces[i] == tsu) id = i;
274 if (id==-1) return;
275 updSld_TwkSurf(id);
276 }
277
updSld_TwkSurf(int id)278 void CGui::updSld_TwkSurf(int id)
279 {
280 if (id < 0 || id >= pGame->surfaces.size()) return;
281 idTwkSurf = id;
282
283 TRACKSURFACE* su = &pGame->surfaces[id];
284 svSuFrict.UpdF(&su->friction); svSuFrictX.UpdF(&su->frictionX); svSuFrictY.UpdF(&su->frictionY);
285 svSuBumpWave.UpdF(&su->bumpWaveLength); svSuBumpAmp.UpdF(&su->bumpAmplitude);
286 svSuBumpWave2.UpdF(&su->bumpWaveLength2); svSuBumpAmp2.UpdF(&su->bumpAmplitude2);
287 svSuRollDrag.UpdF(&su->rollingDrag); svSuRollRes.UpdF(&su->rollingResist);
288 //cmbSurfTire
289 //cmbSurfType->setIndexSelected(su->type);
290 }
291
comboSurfTire(Cmb cmb,size_t val)292 void CGui::comboSurfTire(Cmb cmb, size_t val)
293 {
294 if (idTwkSurf==-1) return;
295 // find tire for name
296 string s = cmb->getItemNameAt(val);
297 s = s.substr(7);
298 int id = pGame->tires_map[s]-1;
299 if (id == -1) return;
300 pGame->surfaces[idTwkSurf].tire = &pGame->tires[id];
301 }
302
comboSurfType(Cmb cmb,size_t val)303 void CGui::comboSurfType(Cmb cmb, size_t val)
304 {
305 if (idTwkSurf==-1) return;
306 pGame->surfaces[idTwkSurf].type = TRACKSURFACE::TYPE(val);
307 }
308
309
310 // collisions
311 //-----------------------------------------------------------------------------------------------------------
312
TweakColSave()313 void CGui::TweakColSave()
314 {
315 String text = edTweakCol->getCaption();
316 if (text == "") return;
317 text = StringUtil::replaceAll(text, "##", "#");
318 //text = StringUtil::replaceAll(text, "#E5F4FF", ""); //!
319
320 std::string path = PATHMANAGER::DataUser() + "/trees";
321 PATHMANAGER::CreateDir(path);
322 path += "/collisions.xml";
323 std::ofstream fo(path.c_str());
324 fo << text.c_str();
325 fo.close();
326 TweakColUpd(true);
327
328 app->scn->data->objs->LoadXml();
329 LogO(String("**** Loaded Vegetation objects: ") + toStr(app->scn->data->objs->colsMap.size()));
330 app->NewGame();
331 }
332
TweakColUpd(bool user)333 void CGui::TweakColUpd(bool user)
334 {
335 txtTweakPathCol->setCaption(TR(user ? "#{TweakUser}" : "#{TweakOriginal}"));
336 txtTweakPathCol->setTextColour(user ? Colour(1,1,0.5) : Colour(0.5,1,1));
337 }
338
TweakColLoad()339 void CGui::TweakColLoad()
340 {
341 bool user = true;
342 std::string name = "/trees/collisions.xml", // user
343 file = PATHMANAGER::DataUser() + name;
344 if (!PATHMANAGER::FileExists(file)) // original
345 { file = PATHMANAGER::Data() + name; user = false; }
346
347 std::ifstream fi(file.c_str());
348 String text = "", s;
349 while (getline(fi,s))
350 text += s + "\n";
351 fi.close();
352
353 text = StringUtil::replaceAll(text, "#", "##");
354 //text = StringUtil::replaceAll(text, "#E5F4FF", ""); //!
355 edTweakCol->setCaption(UString(text));
356
357 TweakColUpd(user);
358
359 MyGUI::InputManager::getInstance().resetKeyFocusWidget();
360 MyGUI::InputManager::getInstance().setKeyFocusWidget(edTweakCol);
361 }
362
btnTweakColSave(WP)363 void CGui::btnTweakColSave(WP){ TweakColSave(); }
364
365
366 /// Tweak read / save file
367 //-----------------------------------------------------------------------------------------------------------
TweakToggle()368 void CGui::TweakToggle()
369 {
370 // window
371 bool vis = !app->mWndTweak->getVisible();
372 app->mWndTweak->setVisible(vis);
373
374 std::string path, pathUser, pathUserDir;
375 bool user = GetCarPath(&path, &pathUser, &pathUserDir, pSet->game.car[0]);
376
377 // load if car changed
378 static string lastPath = "";
379 if (lastPath != path || app->ctrl) // force reload ctrl-alt-Z
380 { lastPath = path;
381
382 TweakCarLoad();
383 TweakColLoad();
384 FillTweakLists();
385 }
386
387 // save and reload shift-alt-Z
388 if (!vis && app->shift)
389 if (tabTweak && tabTweak->getIndexSelected() < 2)
390 TweakCarSave();
391 else
392 TweakColSave();
393 }
394
tabCarEdChng(Tab,size_t id)395 void CGui::tabCarEdChng(Tab, size_t id)
396 {
397 pSet->car_ed_tab = id;
398 }
tabTweakChng(Tab,size_t id)399 void CGui::tabTweakChng(Tab, size_t id)
400 {
401 pSet->tweak_tab = id;
402 }
403
404
405 // Get car file path
GetCarPath(std::string * pathCar,std::string * pathSave,std::string * pathSaveDir,std::string carname,bool forceOrig)406 bool CGui::GetCarPath(std::string* pathCar,
407 std::string* pathSave, std::string* pathSaveDir,
408 std::string carname, bool forceOrig)
409 {
410 std::string file = carname + ".car",
411 pathOrig = PATHMANAGER::CarSim() + "/" + pSet->game.sim_mode + "/cars/" + file,
412 pathUserD = PATHMANAGER::CarSimU() + "/" + pSet->game.sim_mode + "/cars/",
413 pathUser = pathUserD + file;
414
415 if (pathSave) *pathSave = pathUser;
416 if (pathSaveDir) *pathSaveDir = pathUserD;
417
418 if (!forceOrig && PATHMANAGER::FileExists(pathUser))
419 {
420 *pathCar = pathUser;
421 return true;
422 }
423 *pathCar = pathOrig;
424 return false;
425 }
426
427
428 // Tire edit const
429 //----------------------------------------------------------------------------------------------------------------------
430 const String CGui::csLateral[15][2] = {
431 " a0","#F0FFFFShape factor",
432 " a1","#C0E0FFLoad infl. on friction coeff",
433 " a2","#F0FFFFLateral friction coeff at load = 0",
434 " a3","#F0FFFFMaximum stiffness",
435 " a4","#F0FFFFLoad at maximum stiffness",
436 " a5","#C0E0FF-Camber infl. on stiffness",
437 " a6","Curvature change with load",
438 " a7","Curvature at load = 0",
439 " a8","#A0C0D0 -Horiz. shift because of camber",
440 " a9"," Load infl. on horizontal shift",
441 " a10"," Horizontal shift at load = 0",
442 "a111"," -Camber infl. on vertical shift",
443 "a112"," -Camber infl. on vertical shift",
444 " a12"," Load infl. on vertical shift",
445 " a13"," Vertical shift at load = 0" };
446 const String CGui::csLongit[13][2] = {
447 " b0","#FFFFF0Shape factor",
448 " b1","#F0F0A0Load infl. on long. friction coeff",
449 " b2","#FFFFF0Longit. friction coeff at load = 0",
450 " b3","#F0F0A0Curvature factor of stiffness",
451 " b4","#F0F0A0Change of stiffness with load at load = 0",
452 " b5","#E0C080Change of progressivity/load", //of stiffness
453 " b6","Curvature change with load^2",
454 " b7","Curvature change with load",
455 " b8","Curvature at load = 0",
456 " b9","#D0D0A0 Load infl. on horizontal shift",
457 " b10"," Horizontal shift at load = 0",
458 " b11"," Load infl. on vertical shift",
459 " b12"," Vertical shift at load = 0" };
460 const String CGui::csAlign[18][2] = {
461 " c0","#E0FFE0Shape factor",
462 " c1","Load infl. of peak value",
463 " c2","Load infl. of peak value",
464 " c3","Curvature factor of stiffness",
465 " c4","Change of stiffness with load at load = 0",
466 " c5","Change of progressivity/load",
467 " c6","-Camber infl. on stiffness",
468 " c7","Curvature change with load",
469 " c8","Curvature change with load",
470 " c9","Curvature at load = 0",
471 "c10","-Camber infl. of stiffness",
472 "c11"," -Camber infl. on horizontal shift",
473 "c12"," Load infl. on horizontal shift",
474 "c13"," Horizontal shift at load = 0",
475 "c14"," -Camber infl. on vertical shift",
476 "c15"," -Camber infl. on vertical shift",
477 "c16"," Load infl. on vertical shift",
478 "c17"," Vertical shift at load = 0" };
479 const String CGui::sCommon = "#C8C8F0Pacejka's Magic Formula coeffs\n";
480
481
482 // Save Tire
TweakTireSave()483 void CGui::TweakTireSave()
484 {
485 //Nope todos: sliders for vals=
486 // jump to section-, help on current line=
487 // ed find text? syntax clr?=
488
489 txtTweakTire->setCaption("");
490 if (app->carModels.size() < 1) return;
491 CAR* pCar = app->carModels[0]->pCar;
492 if (!pCar) return;
493
494 const CARTIRE* tire = app->carModels[0]->pCar->dynamics.GetTire(FRONT_LEFT);
495 if (!tire) return;
496 const std::vector <Dbl>& a = tire->lateral, b = tire->longitudinal, c = tire->aligning;
497
498 string name = edTweakTireSet->getCaption();
499 string pathUserT = PATHMANAGER::CarSimU() + "/" + pSet->game.sim_mode + "/tires/";
500 PATHMANAGER::CreateDir(pathUserT);
501 string file = pathUserT+"/"+name+".tire";
502 if (PATHMANAGER::FileExists(file))
503 {
504 txtTweakTire->setCaption(TR("#FF3030#{AlreadyExists}."));
505 return;
506 }
507
508 ofstream fo(file.c_str()); int i=0;
509
510 fo << "[ params ]\n";
511 fo << "#-------- Lateral force\n"; i = 0;
512 fo << "a0="<< a[i++] << " # Shape factor A0\n";
513 fo << "a1="<< a[i++] << " # Load infl. on lat. friction coeff (*1000) (1/kN) A1\n";
514 fo << "a2="<< a[i++] << " # Lateral friction coefficient at load = 0 (*1000) 2\n";
515 fo << "a3="<< a[i++] << " # Maximum stiffness (N/deg) A3\n";
516 fo << "a4="<< a[i++] << " # Load at maximum stiffness (kN) A4\n";
517 fo << "a5="<< a[i++] << " # Camber influence on stiffness (%/deg/100) A5\n";
518 fo << "a6="<< a[i++] << " # Curvature change with load A6\n";
519 fo << "a7="<< a[i++] << " # Curvature at load = 0 A7\n";
520 fo << "a8="<< a[i++] << " # Horizontal shift because of camber (deg/deg) A8\n";
521 fo << "a9="<< a[i++] << " # Load influence on horizontal shift (deg/kN) A9\n";
522 fo << "a10="<< a[i++] << " # Horizontal shift at load = 0 (deg) A10\n";
523 fo << "a111="<<a[i++] << " # Camber influence on vertical shift (N/deg/kN) A11.1\n";
524 fo << "a112="<<a[i++] << " # Camber influence on vertical shift (N/deg/kN**2) A11.2\n";
525 fo << "a12="<< a[i++] << " # Load influence on vertical shift (N/kN) A12\n";
526 fo << "a13="<< a[i++] << " # Vertical shift at load = 0 (N) A13\n";
527 fo << "#-------- Longitudinal force\n"; i = 0;
528 fo << "b0="<< b[i++] << " # Shape factor B0\n";
529 fo << "b1="<< b[i++] << " # Load infl. on long. friction coeff (*1000) (1/kN) B1\n";
530 fo << "b2="<< b[i++] << " # Longitudinal friction coefficient at load = 0 (*1000) B2\n";
531 fo << "b3="<< b[i++] << " # Curvature factor of stiffness (N/%/kN**2) B3\n";
532 fo << "b4="<< b[i++] << " # Change of stiffness with load at load = 0 (N/%/kN) B4\n";
533 fo << "b5="<< b[i++] << " # Change of progressivity of stiffness/load (1/kN) B5\n";
534 fo << "b6="<< b[i++] << " # Curvature change with load B6\n";
535 fo << "b7="<< b[i++] << " # Curvature change with load B7\n";
536 fo << "b8="<< b[i++] << " # Curvature at load = 0 B8\n";
537 fo << "b9="<< b[i++] << " # Load influence on horizontal shift (%/kN) B9\n";
538 fo << "b10="<<b[i++] << " # Horizontal shift at load = 0 (%) B10\n";
539 fo << "#--------- Aligning moment\n"; i = 0;
540 fo << "c0="<< c[i++] << " # Shape factor C0\n";
541 fo << "c1="<< c[i++] << " # Load influence of peak value (Nm/kN**2) C1\n";
542 fo << "c2="<< c[i++] << " # Load influence of peak value (Nm/kN) C2\n";
543 fo << "c3="<< c[i++] << " # Curvature factor of stiffness (Nm/deg/kN**2) C3\n";
544 fo << "c4="<< c[i++] << " # Change of stiffness with load at load = 0 (Nm/deg/kN) C4\n";
545 fo << "c5="<< c[i++] << " # Change of progressivity of stiffness/load (1/kN) C5\n";
546 fo << "c6="<< c[i++] << " # Camber influence on stiffness (%/deg/100) C6\n";
547 fo << "c7="<< c[i++] << " # Curvature change with load C7\n";
548 fo << "c8="<< c[i++] << " # Curvature change with load C8\n";
549 fo << "c9="<< c[i++] << " # Curvature at load = 0 C9\n";
550 fo << "c10="<<c[i++] << " # Camber influence of stiffness C10\n";
551 fo << "c11="<<c[i++] << " # Camber influence on horizontal shift (deg/deg) C11\n";
552 fo << "c12="<<c[i++] << " # Load influence on horizontal shift (deg/kN) C12\n";
553 fo << "c13="<<c[i++] << " # Horizontal shift at load = 0 (deg) C13\n";
554 fo << "c14="<<c[i++] << " # Camber influence on vertical shift (Nm/deg/kN**2) C14\n";
555 fo << "c15="<<c[i++] << " # Camber influence on vertical shift (Nm/deg/kN) C15\n";
556 fo << "c16="<<c[i++] << " # Load influence on vertical shift (Nm/kN) C16\n";
557 fo << "c17="<<c[i++] << " # Vertical shift at load = 0 (Nm) C17\n";
558 fo << "#---------\n";
559
560
561 txtTweakTire->setCaption(TR("#30FF30#{Saved}."));
562
563 // LoadTires in game thread, FillTweakLists after, in render
564 sTireLoad = name;
565 pGame->reloadSimNeed = true;
566 }
567
568
569 // reset all
btnTweakTireReset(WP)570 void CGui::btnTweakTireReset(WP)
571 {
572 pGame->reloadSimNeed = true;
573 txtTweakTire->setCaption(TR("#FF9030#{Reset}."));
574 }
575