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