1 /***************************************************************************
2 
3     file                 : driver.cpp
4     created              : Thu Dec 20 01:21:49 CET 2002
5     copyright            : (C) 2002-2004 Bernhard Wymann
6     email                : berniw@bluewin.ch
7     version              : $Id: driver.cpp,v 1.1.2.2 2008/12/31 03:53:53 berniw Exp $
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19 
20 #include "driver.h"
21 
22 const float Driver::MAX_UNSTUCK_ANGLE = 15.0f/180.0f*PI;	// [radians] If the angle of the car on the track is smaller, we assume we are not stuck.
23 const float Driver::UNSTUCK_TIME_LIMIT = 2.0f;				// [s] We try to get unstuck after this time.
24 const float Driver::MAX_UNSTUCK_SPEED = 5.0f;				// [m/s] Below this speed we consider being stuck.
25 const float Driver::MIN_UNSTUCK_DIST = 3.0f;				// [m] If we are closer to the middle we assume to be not stuck.
26 const float Driver::G = 9.81f;								// [m/(s*s)] Welcome on Earth.
27 const float Driver::FULL_ACCEL_MARGIN = 1.0f;				// [m/s] Margin reduce oscillation of brake/acceleration.
28 const float Driver::SHIFT = 0.9f;							// [-] (% of rpmredline) When do we like to shift gears.
29 const float Driver::SHIFT_MARGIN = 4.0f;					// [m/s] Avoid oscillating gear changes.
30 const float Driver::ABS_SLIP = 2.0f;						// [m/s] range [0..10]
31 const float Driver::ABS_RANGE = 5.0f;						// [m/s] range [0..10]
32 const float Driver::ABS_MINSPEED = 3.0f;					// [m/s] Below this speed the ABS is disabled (numeric, division by small numbers).
33 const float Driver::TCL_SLIP = 2.0f;						// [m/s] range [0..10]
34 const float Driver::TCL_RANGE = 10.0f;						// [m/s] range [0..10]
35 const float Driver::LOOKAHEAD_CONST = 17.0f;				// [m]
36 const float Driver::LOOKAHEAD_FACTOR = 0.33f;				// [-]
37 const float Driver::WIDTHDIV = 3.0f;						// [-] Defines the percentage of the track to use (2/WIDTHDIV).
38 const float Driver::SIDECOLL_MARGIN = 3.0f;					// [m] Distance between car centers to avoid side collisions.
39 const float Driver::BORDER_OVERTAKE_MARGIN = 0.5f;			// [m]
40 const float Driver::OVERTAKE_OFFSET_SPEED = 5.0f;			// [m/s] Offset change speed.
41 const float Driver::PIT_LOOKAHEAD = 6.0f;					// [m] Lookahead to stop in the pit.
42 const float Driver::PIT_BRAKE_AHEAD = 200.0f;				// [m] Workaround for "broken" pitentries.
43 const float Driver::PIT_MU = 0.4f;							// [-] Friction of pit concrete.
44 const float Driver::MAX_SPEED = 84.0f;						// [m/s] Speed to compute the percentage of brake to apply.
45 const float Driver::MAX_FUEL_PER_METER = 0.0008f;			// [liter/m] fuel consumtion.
46 const float Driver::CLUTCH_SPEED = 5.0f;					// [m/s]
47 const float Driver::CENTERDIV = 0.1f;						// [-] (factor) [0.01..0.6].
48 const float Driver::DISTCUTOFF = 200.0f;					// [m] How far to look, terminate while loops.
49 const float Driver::MAX_INC_FACTOR = 5.0f;					// [m] Increment faster if speed is slow [1.0..10.0].
50 const float Driver::CATCH_FACTOR = 10.0f;					// [-] select MIN(catchdist, dist*CATCH_FACTOR) to overtake.
51 const float Driver::CLUTCH_FULL_MAX_TIME = 2.0f;			// [s] Time to apply full clutch.
52 const float Driver::USE_LEARNED_OFFSET_RANGE = 0.2f;		// [m] if offset < this use the learned stuff
53 
54 const float Driver::TEAM_REAR_DIST = 50.0f;					//
55 const int Driver::TEAM_DAMAGE_CHANGE_LEAD = 700;			// When to change position in the team?
56 
57 // Static variables.
58 Cardata *Driver::cardata = NULL;
59 double Driver::currentsimtime;
60 
61 
Driver(int index)62 Driver::Driver(int index)
63 {
64 	INDEX = index;
65 }
66 
67 
~Driver()68 Driver::~Driver()
69 {
70 	delete opponents;
71 	delete pit;
72 	delete [] radius;
73 	delete learn;
74 	delete strategy;
75 	if (cardata != NULL) {
76 		delete cardata;
77 		cardata = NULL;
78 	}
79 }
80 
81 
82 // Called for every track change or new race.
initTrack(tTrack * t,void * carHandle,void ** carParmHandle,tSituation * s)83 void Driver::initTrack(tTrack* t, void *carHandle, void **carParmHandle, tSituation *s)
84 {
85 	track = t;
86 
87 	const int BUFSIZE = 256;
88 	char buffer[BUFSIZE];
89 	// Load a custom setup if one is available.
90 	// Get a pointer to the first char of the track filename.
91 	char* trackname = strrchr(track->filename, '/') + 1;
92 
93 	switch (s->_raceType) {
94 		case RM_TYPE_PRACTICE:
95 			snprintf(buffer, BUFSIZE, "drivers/damned/%d/practice/%s", INDEX, trackname);
96 			break;
97 		case RM_TYPE_QUALIF:
98 			snprintf(buffer, BUFSIZE, "drivers/damned/%d/qualifying/%s", INDEX, trackname);
99 			break;
100 		case RM_TYPE_RACE:
101 			snprintf(buffer, BUFSIZE, "drivers/damned/%d/race/%s", INDEX, trackname);
102 			break;
103 		default:
104 			break;
105 	}
106 
107 	*carParmHandle = GfParmReadFile(buffer, GFPARM_RMODE_STD);
108 	if (*carParmHandle == NULL) {
109 		snprintf(buffer, BUFSIZE, "drivers/damned/%d/default.xml", INDEX);
110 		*carParmHandle = GfParmReadFile(buffer, GFPARM_RMODE_STD);
111     }
112 
113 	// Create a pit stop strategy object.
114 	strategy = new SimpleStrategy2();
115 
116 	// Init fuel.
117 	strategy->setFuelAtRaceStart(t, carParmHandle, s, INDEX);
118 
119 	// Load and set parameters.
120 	MU_FACTOR = GfParmGetNum(*carParmHandle, BT_SECT_PRIV, BT_ATT_MUFACTOR, (char*)NULL, 0.69f);
121 }
122 
123 
124 // Start a new race.
newRace(tCarElt * car,tSituation * s)125 void Driver::newRace(tCarElt* car, tSituation *s)
126 {
127 	float deltaTime = (float) RCM_MAX_DT_ROBOTS;
128 	MAX_UNSTUCK_COUNT = int(UNSTUCK_TIME_LIMIT/deltaTime);
129 	OVERTAKE_OFFSET_INC = OVERTAKE_OFFSET_SPEED*deltaTime;
130 	stuck = 0;
131 	alone = 1;
132 	clutchtime = 0.0f;
133 	oldlookahead = 0.0f;
134 	this->car = car;
135 	CARMASS = GfParmGetNum(car->_carHandle, SECT_CAR, PRM_MASS, NULL, 1000.0f);
136 	myoffset = 0.0f;
137 	initCa();
138 	initCw();
139 	initTireMu();
140 	initTCLfilter();
141 
142 	// Create just one instance of cardata shared by all drivers.
143 	if (cardata == NULL) {
144 		cardata = new Cardata(s);
145 	}
146 	mycardata = cardata->findCar(car);
147 	currentsimtime = s->currentTime;
148 
149 	// initialize the list of opponents.
150 	opponents = new Opponents(s, this, cardata);
151 	opponent = opponents->getOpponentPtr();
152 
153 	// Set team mate.
154 	const char *teammate = GfParmGetStr(car->_carHandle, BT_SECT_PRIV, BT_ATT_TEAMMATE, NULL);
155 	if (teammate != NULL) {
156 		opponents->setTeamMate(teammate);
157 	}
158 
159 	// Initialize radius of segments.
160 	radius = new float[track->nseg];
161 	computeRadius(radius);
162 
163 	learn = new SegLearn(track, s, INDEX);
164 
165 	// create the pit object.
166 	pit = new Pit(s, this);
167 }
168 
169 
170 // Drive during race.
drive(tSituation * s)171 void Driver::drive(tSituation *s)
172 {
173 	memset(&car->ctrl, 0, sizeof(tCarCtrl));
174 
175 	update(s);
176 
177 	//pit->setPitstop(true);
178 
179 	if (isStuck()) {
180 		car->_steerCmd = -mycardata->getCarAngle() / car->_steerLock;
181 		car->_gearCmd = -1;		// Reverse gear.
182 		car->_accelCmd = 1.0f;	// 100% accelerator pedal.
183 		car->_brakeCmd = 0.0f;	// No brakes.
184 		car->_clutchCmd = 0.0f;	// Full clutch (gearbox connected with engine).
185 	} else {
186 		car->_steerCmd = filterSColl(getSteer());
187 		car->_gearCmd = getGear();
188 		car->_brakeCmd = filterABS(filterBrakeSpeed(filterBColl(filterBPit(getBrake()))));
189 		if (car->_brakeCmd == 0.0f) {
190 			car->_accelCmd = filterTCL(filterTrk(filterOverlap(getAccel())));
191 		} else {
192 			car->_accelCmd = 0.0f;
193   		}
194 		car->_clutchCmd = getClutch();
195 
196 	}
197 }
198 
199 
200 // Set pitstop commands.
pitCommand(tSituation * s)201 int Driver::pitCommand(tSituation *s)
202 {
203 	car->_pitRepair = strategy->pitRepair(car, s);
204 	car->_pitFuel = strategy->pitRefuel(car, s);
205 	// This should be the only place where the pit stop is set to false!
206 	pit->setPitstop(false);
207 	return ROB_PIT_IM; // return immediately.
208 }
209 
210 
211 // End of the current race.
endRace(tSituation * s)212 void Driver::endRace(tSituation *s)
213 {
214 	// Nothing for now.
215 }
216 
217 
218 /***************************************************************************
219  *
220  * utility functions
221  *
222 ***************************************************************************/
223 
224 
computeRadius(float * radius)225 void Driver::computeRadius(float *radius)
226 {
227 	float lastturnarc = 0.0f;
228 	int lastsegtype = TR_STR;
229 
230 	tTrackSeg *currentseg, *startseg = track->seg;
231 	currentseg = startseg;
232 
233 	do {
234 		if (currentseg->type == TR_STR) {
235 			lastsegtype = TR_STR;
236 			radius[currentseg->id] = FLT_MAX;
237 		} else {
238 			if (currentseg->type != lastsegtype) {
239 				float arc = 0.0f;
240 				tTrackSeg *s = currentseg;
241 				lastsegtype = currentseg->type;
242 
243 				while (s->type == lastsegtype && arc < PI/2.0f) {
244 					arc += s->arc;
245 					s = s->next;
246 				}
247 				lastturnarc = arc/(PI/2.0f);
248 			}
249 			radius[currentseg->id] = (currentseg->radius + currentseg->width/2.0)/lastturnarc;
250 		}
251 		currentseg = currentseg->next;
252 	} while (currentseg != startseg);
253 
254 }
255 
256 
257 // Compute the allowed speed on a segment.
getAllowedSpeed(tTrackSeg * segment)258 float Driver::getAllowedSpeed(tTrackSeg *segment)
259 {
260 	float mu = segment->surface->kFriction*TIREMU*MU_FACTOR;
261 	float r = radius[segment->id];
262 	float dr = learn->getRadius(segment);
263 	if (dr < 0.0f) {
264 		r += dr;
265 	} else {
266 		float tdr = dr*(1.0f - MIN(1.0f, fabs(myoffset)*2.0f/segment->width));
267 		r += tdr;
268 	}
269 	// README: the outcommented code is the more save version.
270 	/*if ((alone > 0 && fabs(myoffset) < USE_LEARNED_OFFSET_RANGE) ||
271 		dr < 0.0f
272 	) {
273 		r += dr;
274 	}*/
275 	r = MAX(1.0, r);
276 
277 	return sqrt((mu*G*r)/(1.0f - MIN(1.0f, r*CA*mu/mass)));
278 }
279 
280 
281 // Compute the length to the end of the segment.
getDistToSegEnd()282 float Driver::getDistToSegEnd()
283 {
284 	if (car->_trkPos.seg->type == TR_STR) {
285 		return car->_trkPos.seg->length - car->_trkPos.toStart;
286 	} else {
287 		return (car->_trkPos.seg->arc - car->_trkPos.toStart)*car->_trkPos.seg->radius;
288 	}
289 }
290 
291 
292 // Compute fitting acceleration.
getAccel()293 float Driver::getAccel()
294 {
295 	if (car->_gear > 0) {
296 		float allowedspeed = getAllowedSpeed(car->_trkPos.seg);
297 		if (allowedspeed > car->_speed_x + FULL_ACCEL_MARGIN) {
298 			return 1.0;
299 		} else {
300 			float gr = car->_gearRatio[car->_gear + car->_gearOffset];
301 			float rm = car->_enginerpmRedLine;
302 			return allowedspeed/car->_wheelRadius(REAR_RGT)*gr /rm;
303 		}
304 	} else {
305 		return 1.0;
306 	}
307 }
308 
309 
310 // If we get lapped reduce accelerator.
filterOverlap(float accel)311 float Driver::filterOverlap(float accel)
312 {
313 	int i;
314 	for (i = 0; i < opponents->getNOpponents(); i++) {
315 		if (opponent[i].getState() & OPP_LETPASS) {
316 			return MIN(accel, 0.5f);
317 		}
318 	}
319 	return accel;
320 }
321 
322 
323 // Compute initial brake value.
getBrake()324 float Driver::getBrake()
325 {
326 	// Car drives backward?
327 	if (car->_speed_x < -MAX_UNSTUCK_SPEED) {
328 		// Yes, brake.
329 		return 1.0;
330 	} else {
331 		// We drive forward, normal braking.
332 		tTrackSeg *segptr = car->_trkPos.seg;
333 		float mu = segptr->surface->kFriction;
334 		float maxlookaheaddist = currentspeedsqr/(2.0f*mu*G);
335 		float lookaheaddist = getDistToSegEnd();
336 
337 		float allowedspeed = getAllowedSpeed(segptr);
338 		if (allowedspeed < car->_speed_x) {
339 			return MIN(1.0f, (car->_speed_x-allowedspeed)/(FULL_ACCEL_MARGIN));
340 		}
341 
342 		segptr = segptr->next;
343 		while (lookaheaddist < maxlookaheaddist) {
344 			allowedspeed = getAllowedSpeed(segptr);
345 			if (allowedspeed < car->_speed_x) {
346 				if (brakedist(allowedspeed, mu) > lookaheaddist) {
347 					return 1.0f;
348 				}
349 			}
350 			lookaheaddist += segptr->length;
351 			segptr = segptr->next;
352 		}
353 		return 0.0f;
354 	}
355 }
356 
357 
358 // Compute gear.
getGear()359 int Driver::getGear()
360 {
361 	if (car->_gear <= 0) {
362 		return 1;
363 	}
364 	float gr_up = car->_gearRatio[car->_gear + car->_gearOffset];
365 	float omega = car->_enginerpmRedLine/gr_up;
366 	float wr = car->_wheelRadius(2);
367 
368 	if (omega*wr*SHIFT < car->_speed_x) {
369 		return car->_gear + 1;
370 	} else {
371 		float gr_down = car->_gearRatio[car->_gear + car->_gearOffset - 1];
372 		omega = car->_enginerpmRedLine/gr_down;
373 		if (car->_gear > 1 && omega*wr*SHIFT > car->_speed_x + SHIFT_MARGIN) {
374 			return car->_gear - 1;
375 		}
376 	}
377 	return car->_gear;
378 }
379 
380 
381 // Compute steer value.
getSteer()382 float Driver::getSteer()
383 {
384 	float targetAngle;
385 	vec2f target = getTargetPoint();
386 
387 	targetAngle = atan2(target.y - car->_pos_Y, target.x - car->_pos_X);
388 	targetAngle -= car->_yaw;
389 	NORM_PI_PI(targetAngle);
390 	return targetAngle / car->_steerLock;
391 }
392 
393 
394 // Compute the clutch value.
getClutch()395 float Driver::getClutch()
396 {
397 	if (car->_gear > 1) {
398 		clutchtime = 0.0f;
399 		return 0.0f;
400 	} else {
401 		float drpm = car->_enginerpm - car->_enginerpmRedLine/2.0f;
402 		clutchtime = MIN(CLUTCH_FULL_MAX_TIME, clutchtime);
403 		float clutcht = (CLUTCH_FULL_MAX_TIME - clutchtime)/CLUTCH_FULL_MAX_TIME;
404 		if (car->_gear == 1 && car->_accelCmd > 0.0f) {
405 			clutchtime += (float) RCM_MAX_DT_ROBOTS;
406 		}
407 
408 		if (drpm > 0) {
409 			float speedr;
410 			if (car->_gearCmd == 1) {
411 				// Compute corresponding speed to engine rpm.
412 				float omega = car->_enginerpmRedLine/car->_gearRatio[car->_gear + car->_gearOffset];
413 				float wr = car->_wheelRadius(2);
414 				speedr = (CLUTCH_SPEED + MAX(0.0f, car->_speed_x))/fabs(wr*omega);
415 				float clutchr = MAX(0.0f, (1.0f - speedr*2.0f*drpm/car->_enginerpmRedLine));
416 				return MIN(clutcht, clutchr);
417 			} else {
418 				// For the reverse gear.
419 				clutchtime = 0.0f;
420 				return 0.0f;
421 			}
422 		} else {
423 			return clutcht;
424 		}
425 	}
426 }
427 
428 // Compute target point for steering.
getTargetPoint()429 vec2f Driver::getTargetPoint()
430 {
431 	tTrackSeg *seg = car->_trkPos.seg;
432 	float lookahead;
433 	float length = getDistToSegEnd();
434 	float offset = getOffset();
435 
436 	if (pit->getInPit()) {
437 		// To stop in the pit we need special lookahead values.
438 		if (currentspeedsqr > pit->getSpeedlimitSqr()) {
439 			lookahead = PIT_LOOKAHEAD + car->_speed_x*LOOKAHEAD_FACTOR;
440 		} else {
441 			lookahead = PIT_LOOKAHEAD;
442 		}
443 	} else {
444 		// Usual lookahead.
445 		lookahead = LOOKAHEAD_CONST + car->_speed_x*LOOKAHEAD_FACTOR;
446 		// Prevent "snap back" of lookahead on harsh braking.
447 		float cmplookahead = oldlookahead - car->_speed_x*RCM_MAX_DT_ROBOTS;
448 		if (lookahead < cmplookahead) {
449 			lookahead = cmplookahead;
450 		}
451 	}
452 
453 	oldlookahead = lookahead;
454 
455 	// Search for the segment containing the target point.
456 	while (length < lookahead) {
457 		seg = seg->next;
458 		length += seg->length;
459 	}
460 
461 	length = lookahead - length + seg->length;
462 	float fromstart = seg->lgfromstart;
463 	fromstart += length;
464 
465 	// Compute the target point.
466 	offset = myoffset = pit->getPitOffset(offset, fromstart);
467 
468 	vec2f s;
469 	s.x = (seg->vertex[TR_SL].x + seg->vertex[TR_SR].x)/2.0f;
470 	s.y = (seg->vertex[TR_SL].y + seg->vertex[TR_SR].y)/2.0f;
471 
472 	if ( seg->type == TR_STR) {
473 		vec2f d, n;
474 		n.x = (seg->vertex[TR_EL].x - seg->vertex[TR_ER].x)/seg->length;
475 		n.y = (seg->vertex[TR_EL].y - seg->vertex[TR_ER].y)/seg->length;
476 		n.normalize();
477 		d.x = (seg->vertex[TR_EL].x - seg->vertex[TR_SL].x)/seg->length;
478 		d.y = (seg->vertex[TR_EL].y - seg->vertex[TR_SL].y)/seg->length;
479 		return s + d*length + offset*n;
480 	} else {
481 		vec2f c, n;
482 		c.x = seg->center.x;
483 		c.y = seg->center.y;
484 		float arc = length/seg->radius;
485 		float arcsign = (seg->type == TR_RGT) ? -1.0f : 1.0f;
486 		arc = arc*arcsign;
487 		s = s.rotate(c, arc);
488 
489 		n = c - s;
490 		n.normalize();
491 		return s + arcsign*offset*n;
492 	}
493 }
494 
495 
496 // Compute offset to normal target point for overtaking or let pass an opponent.
getOffset()497 float Driver::getOffset()
498 {
499 	int i;
500 	float catchdist, mincatchdist = FLT_MAX, mindist = -1000.0f;
501 	Opponent *o = NULL;
502 
503 	// Increment speed dependent.
504 	float incfactor = MAX_INC_FACTOR - MIN(fabs(car->_speed_x)/MAX_INC_FACTOR, (MAX_INC_FACTOR - 1.0f));
505 
506 	// Let overlap or let less damaged team mate pass.
507 	for (i = 0; i < opponents->getNOpponents(); i++) {
508 		// Let the teammate with less damage overtake to use slipstreaming.
509 		// The position change happens when the damage difference is greater than
510 		// TEAM_DAMAGE_CHANGE_LEAD.
511 		if (((opponent[i].getState() & OPP_LETPASS) && !opponent[i].isTeamMate()) ||
512 			(opponent[i].isTeamMate() && (car->_dammage - opponent[i].getDamage() > TEAM_DAMAGE_CHANGE_LEAD) &&
513 			(opponent[i].getDistance() > -TEAM_REAR_DIST) && (opponent[i].getDistance() < -car->_dimension_x) &&
514 			car->race.laps == opponent[i].getCarPtr()->race.laps))
515 		{
516 			// Behind, larger distances are smaller ("more negative").
517 			if (opponent[i].getDistance() > mindist) {
518 				mindist = opponent[i].getDistance();
519 				o = &opponent[i];
520 			}
521 		}
522 	}
523 
524 	if (o != NULL) {
525 		tCarElt *ocar = o->getCarPtr();
526 		float side = car->_trkPos.toMiddle - ocar->_trkPos.toMiddle;
527 		float w = car->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN;
528 		if (side > 0.0f) {
529 			if (myoffset < w) {
530 				myoffset += OVERTAKE_OFFSET_INC*incfactor;
531 			}
532 		} else {
533 			if (myoffset > -w) {
534 				myoffset -= OVERTAKE_OFFSET_INC*incfactor;
535 			}
536 		}
537 		return myoffset;
538 	}
539 
540 
541 	// Overtake.
542 	for (i = 0; i < opponents->getNOpponents(); i++) {
543 		if ((opponent[i].getState() & OPP_FRONT) &&
544 			!(opponent[i].isTeamMate() && car->race.laps <= opponent[i].getCarPtr()->race.laps))
545 		{
546 			catchdist = MIN(opponent[i].getCatchDist(), opponent[i].getDistance()*CATCH_FACTOR);
547 			if (catchdist < mincatchdist) {
548 				mincatchdist = catchdist;
549 				o = &opponent[i];
550 			}
551 		}
552 	}
553 
554 	if (o != NULL) {
555 		// Compute the width around the middle which we can use for overtaking.
556 		float w = o->getCarPtr()->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN;
557 		// Compute the opponents distance to the middle.
558 		float otm = o->getCarPtr()->_trkPos.toMiddle;
559 		// Define the with of the middle range.
560 		float wm = o->getCarPtr()->_trkPos.seg->width*CENTERDIV;
561 
562 		if (otm > wm && myoffset > -w) {
563 			myoffset -= OVERTAKE_OFFSET_INC*incfactor;
564 		} else if (otm < -wm && myoffset < w) {
565 			myoffset += OVERTAKE_OFFSET_INC*incfactor;
566 		} else {
567 			// If the opponent is near the middle we try to move the offset toward
568 			// the inside of the expected turn.
569 			// Try to find out the characteristic of the track up to catchdist.
570 			tTrackSeg *seg = car->_trkPos.seg;
571 			float length = getDistToSegEnd();
572 			float oldlen, seglen = length;
573 			float lenright = 0.0f, lenleft = 0.0f;
574 			mincatchdist = MIN(mincatchdist, DISTCUTOFF);
575 
576 			do {
577 				switch (seg->type) {
578 				case TR_LFT:
579 					lenleft += seglen;
580 					break;
581 				case TR_RGT:
582 					lenright += seglen;
583 					break;
584 				default:
585 					// Do nothing.
586 					break;
587 				}
588 				seg = seg->next;
589 				seglen = seg->length;
590 				oldlen = length;
591 				length += seglen;
592 			} while (oldlen < mincatchdist);
593 
594 			// If we are on a straight look for the next turn.
595 			if (lenleft == 0.0f && lenright == 0.0f) {
596 				while (seg->type == TR_STR) {
597 					seg = seg->next;
598 				}
599 				// Assume: left or right if not straight.
600 				if (seg->type == TR_LFT) {
601 					lenleft = 1.0f;
602 				} else {
603 					lenright = 1.0f;
604 				}
605 			}
606 
607 			// Because we are inside we can go to the border.
608 			float maxoff = (o->getCarPtr()->_trkPos.seg->width - car->_dimension_y)/2.0-BORDER_OVERTAKE_MARGIN;
609 			if (lenleft > lenright) {
610 				if (myoffset < maxoff) {
611 					myoffset += OVERTAKE_OFFSET_INC*incfactor;
612 				}
613 			} else {
614 				if (myoffset > -maxoff) {
615 					myoffset -= OVERTAKE_OFFSET_INC*incfactor;
616 				}
617 			}
618 		}
619 	} else {
620 		// There is no opponent to overtake, so the offset goes slowly back to zero.
621 		if (myoffset > OVERTAKE_OFFSET_INC) {
622 			myoffset -= OVERTAKE_OFFSET_INC;
623 		} else if (myoffset < -OVERTAKE_OFFSET_INC) {
624 			myoffset += OVERTAKE_OFFSET_INC;
625 		} else {
626 			myoffset = 0.0f;
627 		}
628 	}
629 
630 	return myoffset;
631 }
632 
633 
634 // Update my private data every timestep.
update(tSituation * s)635 void Driver::update(tSituation *s)
636 {
637 	// Update global car data (shared by all instances) just once per timestep.
638 	if (currentsimtime != s->currentTime) {
639 		currentsimtime = s->currentTime;
640 		cardata->update();
641 	}
642 
643 	// Update the local data rest.
644 	speedangle = mycardata->getTrackangle() - atan2(car->_speed_Y, car->_speed_X);
645 	NORM_PI_PI(speedangle);
646 	mass = CARMASS + car->_fuel;
647 	currentspeedsqr = car->_speed_x*car->_speed_x;
648 	opponents->update(s, this);
649 	strategy->update(car, s);
650 	if (!pit->getPitstop()) {
651 		pit->setPitstop(strategy->needPitstop(car, s));
652 	}
653 	pit->update();
654 	alone = isAlone();
655 	learn->update(s, track, car, alone, myoffset, car->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN, radius);
656 }
657 
658 
isAlone()659 int Driver::isAlone()
660 {
661 	int i;
662 	for (i = 0; i < opponents->getNOpponents(); i++) {
663 		if (opponent[i].getState() & (OPP_COLL | OPP_LETPASS)) {
664 			return 0;	// Not alone.
665 		}
666 	}
667 	return 1;	// Alone.
668 }
669 
670 
671 // Check if I'm stuck.
isStuck()672 bool Driver::isStuck()
673 {
674 	if (fabs(mycardata->getCarAngle()) > MAX_UNSTUCK_ANGLE &&
675 		car->_speed_x < MAX_UNSTUCK_SPEED &&
676 		fabs(car->_trkPos.toMiddle) > MIN_UNSTUCK_DIST) {
677 		if (stuck > MAX_UNSTUCK_COUNT && car->_trkPos.toMiddle*mycardata->getCarAngle() < 0.0) {
678 			return true;
679 		} else {
680 			stuck++;
681 			return false;
682 		}
683 	} else {
684 		stuck = 0;
685 		return false;
686 	}
687 }
688 
689 
690 // Compute aerodynamic downforce coefficient CA.
initCa()691 void Driver::initCa()
692 {
693 	const char *WheelSect[4] = {SECT_FRNTRGTWHEEL, SECT_FRNTLFTWHEEL, SECT_REARRGTWHEEL, SECT_REARLFTWHEEL};
694 	float rearwingarea = GfParmGetNum(car->_carHandle, SECT_REARWING, PRM_WINGAREA, (char*) NULL, 0.0f);
695 	float rearwingangle = GfParmGetNum(car->_carHandle, SECT_REARWING, PRM_WINGANGLE, (char*) NULL, 0.0f);
696 	float wingca = 1.23f*rearwingarea*sin(rearwingangle);
697 
698 	float cl = GfParmGetNum(car->_carHandle, SECT_AERODYNAMICS, PRM_FCL, (char*) NULL, 0.0f) +
699 			   GfParmGetNum(car->_carHandle, SECT_AERODYNAMICS, PRM_RCL, (char*) NULL, 0.0f);
700 	float h = 0.0f;
701 	int i;
702 	for (i = 0; i < 4; i++)
703 		h += GfParmGetNum(car->_carHandle, WheelSect[i], PRM_RIDEHEIGHT, (char*) NULL, 0.20f);
704 	h*= 1.5f; h = h*h; h = h*h; h = 2.0f * exp(-3.0f*h);
705 	CA = h*cl + 4.0f*wingca;
706 }
707 
708 
709 // Compute aerodynamic drag coefficient CW.
initCw()710 void Driver::initCw()
711 {
712 	float cx = GfParmGetNum(car->_carHandle, SECT_AERODYNAMICS, PRM_CX, (char*) NULL, 0.0f);
713 	float frontarea = GfParmGetNum(car->_carHandle, SECT_AERODYNAMICS, PRM_FRNTAREA, (char*) NULL, 0.0f);
714 	CW = 0.645f*cx*frontarea;
715 }
716 
717 
718 // Init the friction coefficient of the the tires.
initTireMu()719 void Driver::initTireMu()
720 {
721 	const char *WheelSect[4] = {SECT_FRNTRGTWHEEL, SECT_FRNTLFTWHEEL, SECT_REARRGTWHEEL, SECT_REARLFTWHEEL};
722 	float tm = FLT_MAX;
723 	int i;
724 
725 	for (i = 0; i < 4; i++) {
726 		tm = MIN(tm, GfParmGetNum(car->_carHandle, WheelSect[i], PRM_MU, (char*) NULL, 1.0f));
727 	}
728 	TIREMU = tm;
729 }
730 
731 
732 // Reduces the brake value such that it fits the speed (more downforce -> more braking).
filterBrakeSpeed(float brake)733 float Driver::filterBrakeSpeed(float brake)
734 {
735 	float weight = (CARMASS + car->_fuel)*G;
736 	float maxForce = weight + CA*MAX_SPEED*MAX_SPEED;
737 	float force = weight + CA*currentspeedsqr;
738 	return brake*force/maxForce;
739 }
740 
741 
742 // Brake filter for pit stop.
filterBPit(float brake)743 float Driver::filterBPit(float brake)
744 {
745 	if (pit->getPitstop() && !pit->getInPit()) {
746 		float dl, dw;
747 		RtDistToPit(car, track, &dl, &dw);
748 		if (dl < PIT_BRAKE_AHEAD) {
749 			float mu = car->_trkPos.seg->surface->kFriction*TIREMU*PIT_MU;
750 			if (brakedist(0.0f, mu) > dl) {
751 				return 1.0f;
752 			}
753 		}
754 	}
755 
756 	if (pit->getInPit()) {
757 		float s = pit->toSplineCoord(car->_distFromStartLine);
758 		// Pit entry.
759 		if (pit->getPitstop()) {
760 			float mu = car->_trkPos.seg->surface->kFriction*TIREMU*PIT_MU;
761 			if (s < pit->getNPitStart()) {
762 				// Brake to pit speed limit.
763 				float dist = pit->getNPitStart() - s;
764 				if (brakedist(pit->getSpeedlimit(), mu) > dist) {
765 					return 1.0f;
766 				}
767 			} else {
768 				// Hold speed limit.
769 				if (currentspeedsqr > pit->getSpeedlimitSqr()) {
770 					return pit->getSpeedLimitBrake(currentspeedsqr);
771 				}
772 			}
773 			// Brake into pit (speed limit 0.0 to stop)
774 			float dist = pit->getNPitLoc() - s;
775 			if (pit->isTimeout(dist)) {
776 				pit->setPitstop(false);
777 				return 0.0f;
778 			} else {
779 				if (brakedist(0.0f, mu) > dist) {
780 					return 1.0f;
781 				} else if (s > pit->getNPitLoc()) {
782 					// Stop in the pit.
783 			 		return 1.0f;
784 				}
785 			}
786 		} else {
787 			// Pit exit.
788 			if (s < pit->getNPitEnd()) {
789 				// Pit speed limit.
790 				if (currentspeedsqr > pit->getSpeedlimitSqr()) {
791 					return pit->getSpeedLimitBrake(currentspeedsqr);
792 				}
793 			}
794 		}
795 	}
796 
797 	return brake;
798 }
799 
800 
801 // Brake filter for collision avoidance.
filterBColl(float brake)802 float Driver::filterBColl(float brake)
803 {
804 	float mu = car->_trkPos.seg->surface->kFriction;
805 	int i;
806 	for (i = 0; i < opponents->getNOpponents(); i++) {
807 		if (opponent[i].getState() & OPP_COLL) {
808 			if (brakedist(opponent[i].getSpeed(), mu) > opponent[i].getDistance()) {
809 				return 1.0f;
810 			}
811 		}
812 	}
813 	return brake;
814 }
815 
816 
817 // Steer filter for collision avoidance.
filterSColl(float steer)818 float Driver::filterSColl(float steer)
819 {
820 	int i;
821 	float sidedist = 0.0f, fsidedist = 0.0f, minsidedist = FLT_MAX;
822 	Opponent *o = NULL;
823 
824 	// Get the index of the nearest car (o).
825 	for (i = 0; i < opponents->getNOpponents(); i++) {
826 		if (opponent[i].getState() & OPP_SIDE) {
827 			sidedist = opponent[i].getSideDist();
828 			fsidedist = fabs(sidedist);
829 			if (fsidedist < minsidedist) {
830 				minsidedist = fsidedist;
831 				o = &opponent[i];
832 			}
833 		}
834 	}
835 
836 	// If there is another car handle the situation.
837 	if (o != NULL) {
838 		float d = fsidedist - o->getWidth();
839 		// Near, so we need to look at it.
840 		if (d < SIDECOLL_MARGIN) {
841 			/* compute angle between cars */
842 			tCarElt *ocar = o->getCarPtr();
843 			float diffangle = ocar->_yaw - car->_yaw;
844 			NORM_PI_PI(diffangle);
845 			// We are near and heading toward the car.
846 			if (diffangle*o->getSideDist() < 0.0f) {
847 				const float c = SIDECOLL_MARGIN/2.0f;
848 				d = d - c;
849 				if (d < 0.0f) {
850 					d = 0.0f;
851 				}
852 
853 				// Steer delta required to drive parallel to the opponent.
854 				float psteer = diffangle/car->_steerLock;
855 				myoffset = car->_trkPos.toMiddle;
856 
857 				// Limit myoffset to suitable limits.
858 				float w = o->getCarPtr()->_trkPos.seg->width/WIDTHDIV-BORDER_OVERTAKE_MARGIN;
859 				if (fabs(myoffset) > w) {
860 					myoffset = (myoffset > 0.0f) ? w : -w;
861 				}
862 
863 				// On straights the car near to the middle can correct more, in turns the car inside
864 				// the turn does (because if you leave the track on the turn "inside" you will skid
865 				// back to the track.
866 				if (car->_trkPos.seg->type == TR_STR) {
867 					if (fabs(car->_trkPos.toMiddle) > fabs(ocar->_trkPos.toMiddle)) {
868 						// Its me, I do correct not that much.
869 						psteer = steer*(d/c) + 1.5f*psteer*(1.0f - d/c);
870 					} else {
871 						// Its the opponent, so I correct more.
872 						psteer = steer*(d/c) + 2.0f*psteer*(1.0f - d/c);
873 					}
874 				} else {
875 					// Who is outside, heavy corrections are less dangerous
876 					// if you drive near the middle of the track.
877 					float outside = car->_trkPos.toMiddle - ocar->_trkPos.toMiddle;
878 					float sign = (car->_trkPos.seg->type == TR_RGT) ? 1.0f : -1.0f;
879 					if (outside*sign > 0.0f) {
880 						psteer = steer*(d/c) + 1.5f*psteer*(1.0f - d/c);
881 					} else {
882 						psteer = steer*(d/c) + 2.0f*psteer*(1.0f - d/c);
883 					}
884 				}
885 
886 				if (psteer*steer > 0.0f && fabs(steer) > fabs(psteer)) {
887 					return steer;
888 				} else {
889 					return psteer;
890 				}
891 			}
892 		}
893 	}
894 	return steer;
895 }
896 
897 
898 // Antilocking filter for brakes.
filterABS(float brake)899 float Driver::filterABS(float brake)
900 {
901 	if (car->_speed_x < ABS_MINSPEED) return brake;
902 	int i;
903 	float slip = 0.0f;
904 	for (i = 0; i < 4; i++) {
905 		slip += car->_wheelSpinVel(i) * car->_wheelRadius(i);
906 	}
907 	slip = car->_speed_x - slip/4.0f;
908 	if (slip > ABS_SLIP) {
909 		brake = brake - MIN(brake, (slip - ABS_SLIP)/ABS_RANGE);
910 	}
911 	return brake;
912 }
913 
914 
915 // TCL filter for accelerator pedal.
filterTCL(float accel)916 float Driver::filterTCL(float accel)
917 {
918 	float slip = (this->*GET_DRIVEN_WHEEL_SPEED)() - car->_speed_x;
919 	if (slip > TCL_SLIP) {
920 		accel = accel - MIN(accel, (slip - TCL_SLIP)/TCL_RANGE);
921 	}
922 	return accel;
923 }
924 
925 
926 // Traction Control (TCL) setup.
initTCLfilter()927 void Driver::initTCLfilter()
928 {
929 	const char *traintype = GfParmGetStr(car->_carHandle, SECT_DRIVETRAIN, PRM_TYPE, VAL_TRANS_RWD);
930 	if (strcmp(traintype, VAL_TRANS_RWD) == 0) {
931 		GET_DRIVEN_WHEEL_SPEED = &Driver::filterTCL_RWD;
932 	} else if (strcmp(traintype, VAL_TRANS_FWD) == 0) {
933 		GET_DRIVEN_WHEEL_SPEED = &Driver::filterTCL_FWD;
934 	} else if (strcmp(traintype, VAL_TRANS_4WD) == 0) {
935 		GET_DRIVEN_WHEEL_SPEED = &Driver::filterTCL_4WD;
936 	}
937 }
938 
939 
940 // TCL filter plugin for rear wheel driven cars.
filterTCL_RWD()941 float Driver::filterTCL_RWD()
942 {
943 	return (car->_wheelSpinVel(REAR_RGT) + car->_wheelSpinVel(REAR_LFT)) *
944 			car->_wheelRadius(REAR_LFT) / 2.0f;
945 }
946 
947 
948 // TCL filter plugin for front wheel driven cars.
filterTCL_FWD()949 float Driver::filterTCL_FWD()
950 {
951 	return (car->_wheelSpinVel(FRNT_RGT) + car->_wheelSpinVel(FRNT_LFT)) *
952 			car->_wheelRadius(FRNT_LFT) / 2.0f;
953 }
954 
955 
956 // TCL filter plugin for all wheel driven cars.
filterTCL_4WD()957 float Driver::filterTCL_4WD()
958 {
959 	return ((car->_wheelSpinVel(FRNT_RGT) + car->_wheelSpinVel(FRNT_LFT)) *
960 			car->_wheelRadius(FRNT_LFT) +
961 		   (car->_wheelSpinVel(REAR_RGT) + car->_wheelSpinVel(REAR_LFT)) *
962 			car->_wheelRadius(REAR_LFT)) / 4.0f;
963 }
964 
965 
966 // Hold car on the track.
filterTrk(float accel)967 float Driver::filterTrk(float accel)
968 {
969 	tTrackSeg* seg = car->_trkPos.seg;
970 
971 	if (car->_speed_x < MAX_UNSTUCK_SPEED ||		// Too slow.
972 		pit->getInPit() ||							// Pit stop.
973 		car->_trkPos.toMiddle*speedangle > 0.0f)	// Speedvector points to the inside of the turn.
974 	{
975 		return accel;
976 	}
977 
978 	if (seg->type == TR_STR) {
979 		float tm = fabs(car->_trkPos.toMiddle);
980 		float w = (seg->width - car->_dimension_y)/2.0f ;
981 		if (tm > w) {
982 			return 0.0f;
983 		} else {
984 			return accel;
985 		}
986 	} else {
987 		float sign = (seg->type == TR_RGT) ? -1.0f : 1.0f;
988 		if (car->_trkPos.toMiddle*sign > 0.0f) {
989 			return accel;
990 		} else {
991 			float tm = fabs(car->_trkPos.toMiddle);
992 			float w = seg->width/WIDTHDIV;
993 			if (tm > w) {
994 				return 0.0f;
995 			} else {
996 				return accel;
997 			}
998 		}
999 	}
1000 }
1001 
1002 
1003 // Compute the needed distance to brake.
brakedist(float allowedspeed,float mu)1004 float Driver::brakedist(float allowedspeed, float mu)
1005 {
1006 	float c = mu*G;
1007 	float d = (CA*mu + CW)/mass;
1008 	float v1sqr = currentspeedsqr;
1009 	float v2sqr = allowedspeed*allowedspeed;
1010 	return -log((c + v2sqr*d)/(c + v1sqr*d))/(2.0f*d);
1011 }
1012 
1013