1 #include "pch.h"
2 #include "common/Def_Str.h"
3 #include "common/data/CData.h"
4 #include "common/data/TracksXml.h"
5 #include "common/GuiCom.h"
6 #include "../vdrift/pathmanager.h"
7 #include "../vdrift/game.h"
8 #include "../road/Road.h"
9 #include "CGame.h"
10 #include "CHud.h"
11 #include "CGui.h"
12 #include "common/MultiList2.h"
13 using namespace std;
14 using namespace Ogre;
15 using namespace MyGUI;
16 
17 
18 ///______________________________________________________________________________________________
19 ///
20 ///  load championship or challenge track
21 ///______________________________________________________________________________________________
Ch_NewGame()22 void App::Ch_NewGame()
23 {
24 	if (pSet->game.champ_num >= (int)data->champs->all.size() ||
25 		pSet->game.chall_num >= (int)data->chall->all.size())  // range
26 	{	pSet->game.champ_num = -1;
27 		pSet->game.chall_num = -1;  }
28 
29 	pGame->timer.end_sim = false;
30 	int iChamp = pSet->game.champ_num;
31 	int iChall = pSet->game.chall_num;
32 	if (iChall >= 0)
33 	{
34 		///  challenge stage
35 		int p = pSet->game.champ_rev ? 1 : 0;
36 		ProgressChall& pc = gui->progressL[p].chs[iChall];
37 		Chall& chl = data->chall->all[iChall];
38 		if (pc.curTrack >= chl.trks.size())  pc.curTrack = 0;  // restart
39 		const ChallTrack& trk = chl.trks[pc.curTrack];
40 		gui->pChall = &chl;  // set
41 
42 		pSet->game.track = trk.name;  pSet->game.track_user = 0;
43 		pSet->game.trackreverse = pSet->game.champ_rev ? !trk.reversed : trk.reversed;
44 		pSet->game.num_laps = trk.laps;
45 
46 		pSet->game.sim_mode = chl.sim_mode;
47 		pSet->game.damage_type = chl.damage_type;
48 		pSet->game.damage_dec = chl.dmg_lap;
49 
50 		pSet->game.boost_type = chl.boost_type;
51 		pSet->game.flip_type = chl.flip_type;
52 		pSet->game.rewind_type = chl.rewind_type;
53 		pSet->game.BoostDefault();  //
54 
55 		//  car not set, and not allowed in chall
56 		if (!gui->IsChallCar(pSet->game.car[0]))  // pick last
57 		{	int cnt = gui->carList->getItemCount();
58 			if (cnt > 0)
59 				pSet->game.car[0] = gui->carList->getItemNameAt(std::min(0,cnt-1)).substr(7);
60 			else
61 			{	LogO("Error: Challenge cars empty!");  return;  }
62 		}
63 		//  set picked car when continuing
64 		if (pc.curTrack > 0 && !pc.car.empty() && !chl.carChng)
65 			pSet->game.car[0] = pc.car;
66 
67 		//TODO: ?challenge icons near denied combos,chkboxes
68 
69 		pSet->game.trees = 1.5f;  //-
70 		pSet->game.collis_veget = true;
71 		pSet->game.dyn_objects = true;  //-
72 
73 		pGame->pause = true;  // wait for stage wnd close
74 		pGame->timer.waiting = true;
75 	}
76 	else if (iChamp >= 0)
77 	{
78 		///  championship stage
79 		int p = pSet->game.champ_rev ? 1 : 0;
80 		ProgressChamp& pc = gui->progress[p].chs[iChamp];
81 		const Champ& ch = data->champs->all[iChamp];
82 		if (pc.curTrack >= ch.trks.size())  pc.curTrack = 0;  // restart
83 		const ChampTrack& trk = ch.trks[pc.curTrack];
84 		pSet->game.track = trk.name;  pSet->game.track_user = 0;
85 		pSet->game.trackreverse = pSet->game.champ_rev ? !trk.reversed : trk.reversed;
86 		pSet->game.num_laps = trk.laps;
87 
88 		pSet->game.boost_type = 1;  // from trk.?
89 		pSet->game.flip_type = 2;
90 		pSet->game.rewind_type = 1;
91 		pSet->game.BoostDefault();  //
92 		//pSet->game.damage_dec = 40.f;  //?
93 		//pSet->game.trees = 1.f;  // >=1 ?
94 		//pSet->game.collis_veget = true;
95 
96 		pGame->pause = true;  // wait for stage wnd close
97 		pGame->timer.waiting = true;
98 	}else
99 	{	pGame->pause = false;  // single race
100 		pGame->timer.waiting = false;
101 	}
102 }
103 
104 
105 ///  car time mul
106 //-----------------------------------------------------------------------------------------------
GetCarTimeMul(const string & car,const string & sim_mode)107 float App::GetCarTimeMul(const string& car, const string& sim_mode)
108 {
109 	//  car factor (time mul, for less power)
110 	float carMul = 1.f;
111 	int id = data->cars->carmap[car];
112 	if (id > 0)
113 	{	const CarInfo& ci = data->cars->cars[id-1];
114 		bool easy = sim_mode == "easy";
115 		carMul = easy ? ci.easy : ci.norm;
116 	}
117 	return carMul;
118 }
119 
120 ///  compute race position,  basing on car and track time
121 //-----------------------------------------------------------------------------------------------
122 
GetRacePos(float timeCur,float timeTrk,float carTimeMul,bool coldStart,float * pPoints)123 int App::GetRacePos(float timeCur, float timeTrk, float carTimeMul, bool coldStart, float* pPoints)
124 {
125 	//  magic factor: seconds needed for 1 second of track time for 1 race place difference
126 	//  eg. if track time is 3min = 180 sec, then 180*magic = 2.16 sec
127 	//  and this is the difference between car race positions (1 and 2, 2 and 3 etc)
128 	//  0.006 .. 0.0012				// par
129 	//float time1pl = magic * timeTrk;
130 
131 	//  if already driving at start, add 1 sec (times are for 1st lap)
132 	float timeC = timeCur + (coldStart ? 0 : 1);
133 	float time = timeC * carTimeMul;
134 
135 	float place = (time - timeTrk)/timeTrk / data->cars->magic;
136 	// time = (place * magic * timeTrk + timeTrk) / carTimeMul;  //todo: show this in lists and hud..
137 	if (pPoints)
138 		*pPoints = std::max(0.f, (20.f - place) * 0.5f);
139 
140 	int plc = place < 1.f ? 1 : std::min(30, (int)( floor(place +1.f) ));
141 	return plc;
142 }
143 
144 
145 ///______________________________________________________________________________________________
146 ///  Load  championships.xml, progress.xml (once)
147 //-----------------------------------------------------------------------------------------------
Ch_XmlLoad()148 void CGui::Ch_XmlLoad()
149 {
150 	/* stats */
151 	float time = 0.f;  int trks = 0;
152 	for (std::map<std::string, float>::const_iterator it = data->tracks->times.begin();
153 		it != data->tracks->times.end(); ++it)
154 	{
155 		const string& trk = (*it).first;
156 		if (trk.substr(0,4) != "Test")
157 		{
158 			time += (*it).second;
159 			++trks;
160 	}	}
161 	LogO("Total tracks: "+ toStr(trks) + ", total time: "+ StrTime2(time/60.f)+" h:m");
162 
163 
164 	#if 0  /* test race pos,points */
165 	float trk = 100.f;
166 	LogO("Test Time "+StrTime(trk)+"   Pos   Points");
167 	for (int i=-5; i <= 20; ++i)
168 	{
169 		float points = 0.f, t = trk + i*1.f;
170 		int pos = GetRacePos(t, trk, 1.0f, true, &points);
171 		LogO("  "+StrTime(t)+"  "+iToStr(pos,2)+"  "+fToStr(points,2,5));
172 	}
173 	#endif
174 
175 
176 ///  Champs  ---------------------------
177 	ProgressXml oldprog[2];
178 	oldprog[0].LoadXml(PATHMANAGER::UserConfigDir() + "/progress.xml");
179 	oldprog[1].LoadXml(PATHMANAGER::UserConfigDir() + "/progress_rev.xml");
180 
181 	int chs = data->champs->all.size();
182 
183 	///  this is for old progress ver loading, from game with newer champs
184 	///  it resets progress only for champs which ver has changed (or track count)
185 	//  fill progress
186 	for (int pr=0; pr < 2; ++pr)
187 	{
188 		progress[pr].chs.clear();
189 		for (int c=0; c < chs; ++c)
190 		{
191 			const Champ& ch = data->champs->all[c];
192 
193 			//  find this champ in loaded progress
194 			bool found = false;  int p = 0;
195 			ProgressChamp* opc = 0;
196 			while (!found && p < oldprog[pr].chs.size())
197 			{
198 				opc = &oldprog[pr].chs[p];
199 				//  same name, ver and trks count
200 				if (opc->name == ch.name && opc->ver == ch.ver &&
201 					opc->trks.size() == ch.trks.size())
202 					found = true;
203 				++p;
204 			}
205 			if (!found)
206 				LogO("|| reset progress for champ: " + ch.name);
207 
208 			ProgressChamp pc;
209 			pc.name = ch.name;  pc.ver = ch.ver;
210 
211 			if (found)  //  found progress, points
212 			{	pc.curTrack = opc->curTrack;
213 				pc.points = opc->points;
214 			}
215 
216 			//  fill tracks
217 			for (int t=0; t < ch.trks.size(); ++t)
218 			{
219 				ProgressTrack pt;
220 				if (found)  // found track points
221 					pt.points = opc->trks[t].points;
222 				pc.trks.push_back(pt);
223 			}
224 
225 			progress[pr].chs.push_back(pc);
226 	}	}
227 	ProgressSave(false);  //will be later in guiInit
228 
229 	if (progress[0].chs.size() != data->champs->all.size() ||
230 		progress[1].chs.size() != data->champs->all.size())
231 		LogO("|| ERROR: champs and progress sizes differ !");
232 
233 
234 ///  Challenges  ---------------------------
235 	ProgressLXml oldpr[2];
236 	oldpr[0].LoadXml(PATHMANAGER::UserConfigDir() + "/progressL.xml");
237 	oldpr[1].LoadXml(PATHMANAGER::UserConfigDir() + "/progressL_rev.xml");
238 
239 	chs = data->chall->all.size();
240 
241 	///  this is for old progress ver loading, from game with newer challs
242 	///  it resets progress only for challs which ver has changed (or track count)
243 	//  fill progress
244 	for (int pr=0; pr < 2; ++pr)
245 	{
246 		progressL[pr].chs.clear();
247 		for (int c=0; c < chs; ++c)
248 		{
249 			const Chall& ch = data->chall->all[c];
250 
251 			//  find this chall in loaded progress
252 			bool found = false;  int p = 0;
253 			ProgressChall* opc = 0;
254 			while (!found && p < oldpr[pr].chs.size())
255 			{
256 				opc = &oldpr[pr].chs[p];
257 				//  same name, ver and trks count
258 				if (opc->name == ch.name && opc->ver == ch.ver &&
259 					opc->trks.size() == ch.trks.size())
260 					found = true;
261 				++p;
262 			}
263 			if (!found)
264 				LogO("|| reset progressL for chall: " + ch.name);
265 
266 			ProgressChall pc;
267 			pc.name = ch.name;  pc.ver = ch.ver;
268 
269 			if (found)
270 			{	//  found progress, copy
271 				pc.curTrack = opc->curTrack;  pc.car = opc->car;
272 				pc.avgPoints = opc->avgPoints;  pc.totalTime = opc->totalTime;
273 				pc.avgPos = opc->avgPos;  pc.fin = opc->fin;
274 			}
275 
276 			//  fill tracks
277 			for (int t=0; t < ch.trks.size(); ++t)
278 			{
279 				ProgressTrackL pt;
280 				if (found)
281 				{	//  found track points
282 					const ProgressTrackL& opt = opc->trks[t];  //pt = opt;
283 					pt.points = opt.points;  pt.time = opt.time;  pt.pos = opt.pos;
284 				}
285 				pc.trks.push_back(pt);
286 			}
287 
288 			progressL[pr].chs.push_back(pc);
289 	}	}
290 	ProgressLSave(false);  //will be later in guiInit
291 
292 	if (progressL[0].chs.size() != data->chall->all.size() ||
293 		progressL[1].chs.size() != data->chall->all.size())
294 		LogO("|] ERROR: challs and progressL sizes differ !");
295 }
296 
297 
298 ///  upd tutor,champ,chall gui vis
299 //-----------------------------------------------------------------------------------------------
UpdChampTabVis()300 void CGui::UpdChampTabVis()
301 {
302 	if (!liChamps || !tabChamp || !btStChamp)  return;
303 	static int oldMenu = pSet->inMenu;
304 	bool tutor = pSet->inMenu == MNU_Tutorial, champ = pSet->inMenu == MNU_Champ, chall = pSet->inMenu == MNU_Challenge;
305 	bool any = tutor || champ || chall;
306 
307 	tabTut->setVisible(tutor);    imgTut->setVisible(tutor);    btStTut->setVisible(tutor);
308 	tabChamp->setVisible(champ);  imgChamp->setVisible(champ);  btStChamp->setVisible(champ);
309 	tabChall->setVisible(chall);  imgChall->setVisible(chall);  btStChall->setVisible(chall);
310 	btNewGameCar->setVisible(!any);
311 
312 	liChamps->setVisible(!chall);  liChamps->setColour(tutor ? Colour(0.85,0.8,0.75) : Colour(0.75,0.8,0.85));
313 	liChalls->setVisible( chall);  liChalls->setColour(Colour(0.74,0.7,0.82));
314 	panCh->setColour(tutor ? Colour(0.9,0.8,0.7) : champ ? Colour(0.7,0.9,0.8) : Colour(0.77,0.75,0.92));
315 
316 	if (oldMenu != pSet->inMenu && any)
317 	{	oldMenu = pSet->inMenu;
318 		if (chall)  ChallsListUpdate();
319 		else        ChampsListUpdate();
320 	}
321 	//if (pSet->inMenu == MNU_Single)
322 	//	BackFromChs();
323 
324 	if (edChInfo->getVisible())  // info texts
325 		edChInfo->setCaption(
326 			chall ? TR("#{ChallInfo2}")+"\n"+TR("#{ChallInfo}") :
327 			 tutor ? TR("#{TutorInfo}")+"\n"+TR("#{ChampInfo}") :
328 					TR("#{ChampInfo2}")+"\n"+TR("#{ChampInfo}"));
329 
330 	btChRestart->setVisible(false);
331 }
332 
btnChampInfo(WP)333 void CGui::btnChampInfo(WP)
334 {
335 	pSet->champ_info = !pSet->champ_info;
336 	if (edChInfo)  edChInfo->setVisible(pSet->champ_info);
337 }
338 
339 
340 ///  add item in stages list
341 //-----------------------------------------------------------------------------------------------
StageListAdd(int n,String name,int laps,String progress)342 void CGui::StageListAdd(int n, String name, int laps, String progress)
343 {
344 	String clr = gcom->GetSceneryColor(name);
345 	liStages->addItem(clr+ toStr(n/10)+toStr(n%10), 0);  int l = liStages->getItemCount()-1;
346 	liStages->setSubItemNameAt(1,l, clr+ name.c_str());
347 
348 	int id = data->tracks->trkmap[name]-1;  if (id < 0)  return;
349 	const TrackInfo& ti = data->tracks->trks[id];
350 
351 	float carMul = app->GetCarTimeMul(pSet->game.car[0], pSet->game.sim_mode);
352 	float time = (data->tracks->times[name] * laps /*laps > 1 -1*/) / carMul;
353 
354 	liStages->setSubItemNameAt(2,l, clr+ ti.scenery);
355 	liStages->setSubItemNameAt(3,l, gcom->clrsDiff[ti.diff]+ TR("#{Diff"+toStr(ti.diff)+"}"));
356 	liStages->setSubItemNameAt(4,l, "#60C0A0  "+toStr(laps));
357 	liStages->setSubItemNameAt(5,l, "#80C0F0 "+StrTime2(time));
358 	liStages->setSubItemNameAt(6,l, progress);
359 }
360 
361 ///  Stages list  sel changed,  update Track info
362 //-----------------------------------------------------------------------------------------------
listStageChng(MyGUI::MultiList2 * li,size_t pos)363 void CGui::listStageChng(MyGUI::MultiList2* li, size_t pos)
364 {
365 	if (valStageNum)  valStageNum->setVisible(pos!=ITEM_NONE);
366 	if (pos==ITEM_NONE)  return;
367 
368 	string trk;  bool rev=false;  int all=1;
369 	if (isChallGui())
370 	{	if (liChalls->getIndexSelected()==ITEM_NONE)  return;
371 		int nch = *liChalls->getItemDataAt<int>(liChalls->getIndexSelected())-1;
372 		if (nch >= data->chall->all.size())  {  LogO("Error chall sel > size.");  return;  }
373 
374 		const Chall& ch = data->chall->all[nch];
375 		if (pos >= ch.trks.size())  {  LogO("Error stage sel > tracks.");  return;  }
376 		trk = ch.trks[pos].name;  rev = ch.trks[pos].reversed;  all = ch.trks.size();
377 
378 		UpdChallDetail(nch);  // stage pass upd txt
379 	}else
380 	{	if (liChamps->getIndexSelected()==ITEM_NONE)  return;
381 		int nch = *liChamps->getItemDataAt<int>(liChamps->getIndexSelected())-1;
382 		if (nch >= data->champs->all.size())  {  LogO("Error champ sel > size.");  return;  }
383 
384 		const Champ& ch = data->champs->all[nch];
385 		if (pos >= ch.trks.size())  {  LogO("Error stage sel > tracks.");  return;  }
386 		trk = ch.trks[pos].name;  rev = ch.trks[pos].reversed;  all = ch.trks.size();
387 	}
388 	if (pSet->gui.champ_rev)  rev = !rev;
389 
390 	if (valTrkNet)  valTrkNet->setCaption(TR("#{Track}: ") + trk);
391 	ReadTrkStatsChamp(trk, rev);
392 	if (valStageNum)  valStageNum->setCaption(toStr(pos+1) +" / "+ toStr(all));
393 }
394 
395 
396 //  stage loaded
Ch_LoadEnd()397 void CGui::Ch_LoadEnd()
398 {
399 	if (pSet->game.champ_num >= 0)
400 	{
401 		ChampFillStageInfo(false);
402 		app->mWndChampStage->setVisible(true);
403 	}
404 	if (pSet->game.chall_num >= 0)
405 	{
406 		ChallFillStageInfo(false);
407 		app->mWndChallStage->setVisible(true);
408 	}
409 }
410 
411 //  Stages gui tab
btnStageNext(WP)412 void CGui::btnStageNext(WP)
413 {
414 	size_t id = liStages->getIndexSelected(), all = liStages->getItemCount();
415 	if (all == 0)  return;
416 	if (id == ITEM_NONE)  id = 0;
417 	else
418 		id = (id +1) % all;
419 	liStages->setIndexSelected(id);
420 	listStageChng(liStages, id);
421 }
422 
btnStagePrev(WP)423 void CGui::btnStagePrev(WP)
424 {
425 	size_t id = liStages->getIndexSelected(), all = liStages->getItemCount();
426 	if (all == 0)  return;
427 	if (id == ITEM_NONE)  id = 0;
428 	id = (id + all -1) % all;
429 	liStages->setIndexSelected(id);
430 	listStageChng(liStages, id);
431 }
432 
433 
434 //  restart progress curtrack
btnChRestart(WP)435 void CGui::btnChRestart(WP)
436 {
437 	int p = pSet->game.champ_rev ? 1 : 0;
438 	if (pSet->inMenu == MNU_Tutorial || pSet->inMenu == MNU_Champ)
439 	{
440 		if (liChamps->getIndexSelected()==ITEM_NONE)  return;
441 		int chId = *liChamps->getItemDataAt<int>(liChamps->getIndexSelected())-1;
442 		ProgressChamp& pc = progress[p].chs[chId];
443 		pc.curTrack = 0;  ChampsListUpdate();
444 	}
445 	else if (pSet->inMenu == MNU_Challenge)
446 	{
447 		if (liChalls->getIndexSelected()==ITEM_NONE)  return;
448 		int chId = *liChalls->getItemDataAt<int>(liChalls->getIndexSelected())-1;
449 		ProgressChall& pc = progressL[p].chs[chId];
450 		pc.curTrack = 0;  ChallsListUpdate();
451 	}
452 }
453