TORCS  1.3.9
The Open Racing Car Simulator
raceengine.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 
3  file : raceengine.cpp
4  created : Sat Nov 23 09:05:23 CET 2002
5  copyright : (C) 2002-2017 by Eric Espie, Bernhard Wymann
6  email : eric.espie@torcs.org
7  version : $Id$
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 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <tgfclient.h>
29 #include <robot.h>
30 #include <raceman.h>
31 #include <racescreens.h>
32 #include <robottools.h>
33 #include <portability.h>
34 
35 #include "racemain.h"
36 #include "racegl.h"
37 #include "raceinit.h"
38 #include "raceresults.h"
39 
40 #include "raceengine.h"
41 
42 static double msgDisp;
43 static double bigMsgDisp;
44 
46 
47 static void ReRaceRules(tCarElt *car);
48 
49 
50 /* Compute Pit stop time */
51 static void
53 {
54  tSituation *s = ReInfo->s;
55  tReCarInfo *info = &(ReInfo->_reCarInfo[car->index]);
56 
57  switch (car->_pitStopType) {
58  case RM_PIT_REPAIR:
59  info->totalPitTime = ReInfo->raceRules.pitstopBaseTime + fabs((double)(car->_pitFuel)) / ReInfo->raceRules.refuelFuelFlow + (tdble)(fabs((double)(car->_pitRepair))) * ReInfo->raceRules.damageRepairFactor + car->_penaltyTime;
60 
61  // Add time for tire change
62  if (car->pitcmd.tireChange == tCarPitCmd::ALL && car->info.skillLevel == 3 && ReInfo->raceRules.tireFactor > 0.0f) {
64  }
65 
67  // Ensure that the right min/max values are in the setup structure (could have been modified by the robot))
68  RtInitCarPitSetup(car->_carHandle, &(car->pitcmd.setup), true);
69  } else {
70  // In case of the race no modifications are allowed, so completely reload the structure
71  RtInitCarPitSetup(car->_carHandle, &(car->pitcmd.setup), false);
72  }
73  car->_scheduledEventTime = s->currentTime + info->totalPitTime;
74  car->_penaltyTime = 0.0f;
75  ReInfo->_reSimItf.reconfig(car);
76  break;
77  case RM_PIT_STOPANDGO:
78  info->totalPitTime = car->_penaltyTime;
79  car->_scheduledEventTime = s->currentTime + info->totalPitTime;
80  car->_penaltyTime = 0.0f;
81  break;
82  }
83 }
84 
85 /* Return from interactive pit information */
86 static void
87 ReUpdtPitCmd(void *pvcar)
88 {
89  tCarElt *car = (tCarElt*)pvcar;
90 
91  ReUpdtPitTime(car);
92  GfuiScreenActivate(ReInfo->_reGameScreen);
93 }
94 
95 static void
97 {
98  if (ReInfo->_reCurTime > msgDisp) {
99  ReSetRaceMsg("");
100  }
101  if (ReInfo->_reCurTime > bigMsgDisp) {
102  ReSetRaceBigMsg("");
103  }
104 }
105 
106 static void
107 ReRaceMsgSet(const char *msg, double life)
108 {
109  if ((ReInfo->_displayMode != RM_DISP_MODE_NONE) && (ReInfo->_displayMode != RM_DISP_MODE_CONSOLE)) {
110  ReSetRaceMsg(msg);
111  msgDisp = ReInfo->_reCurTime + life;
112  }
113 }
114 
115 
116 static void
117 ReRaceBigMsgSet(const char *msg, double life)
118 {
119  if ((ReInfo->_displayMode != RM_DISP_MODE_NONE) && (ReInfo->_displayMode != RM_DISP_MODE_CONSOLE)) {
120  ReSetRaceBigMsg(msg);
121  bigMsgDisp = ReInfo->_reCurTime + life;
122  }
123 }
124 
125 
126 static void
128 {
129  int i, pitok;
130  tTrackSeg *sseg;
131  tdble wseg;
132  static float color[] = {0.5, 0.5, 1.0, 1.0};
133  tSituation *s = ReInfo->s;
134  const int BUFSIZE = 1024;
135  char buf[BUFSIZE];
136 
137  tReCarInfo *info = &(ReInfo->_reCarInfo[car->index]);
138 
139  if (car->_speed_x > car->_topSpeed) {
140  car->_topSpeed = car->_speed_x;
141  }
142 
143  // For practice and qualif.
144  if (car->_speed_x > info->topSpd) {
145  info->topSpd = car->_speed_x;
146  }
147 
148  if (car->_speed_x < info->botSpd) {
149  info->botSpd = car->_speed_x;
150  car->_currentMinSpeedForLap = car->_speed_x;
151  }
152 
153  // Pitstop.
154  if (car->_pit) {
155  if (car->ctrl.raceCmd & RM_CMD_PIT_ASKED) {
156  // Pit already occupied?
157  if (car->_pit->pitCarIndex == TR_PIT_STATE_FREE) {
158  snprintf(car->ctrl.msg[2], 32, "Can Pit");
159  } else {
160  snprintf(car->ctrl.msg[2], 32, "Pit Occupied");
161  }
162 
163  memcpy(car->ctrl.msgColor, color, sizeof(car->ctrl.msgColor));
164  }
165 
166  if (car->_state & RM_CAR_STATE_PIT) {
167  car->ctrl.raceCmd &= ~RM_CMD_PIT_ASKED; // clear the flag.
168  if (car->_scheduledEventTime < s->currentTime) {
169  car->_state &= ~RM_CAR_STATE_PIT;
170  car->_pit->pitCarIndex = TR_PIT_STATE_FREE;
171  snprintf(buf, BUFSIZE, "%s pit stop %.1fs", car->_name, info->totalPitTime);
172  ReRaceMsgSet(buf, 5);
173  } else {
174  snprintf(car->ctrl.msg[2], 32, "in pits %.1fs", s->currentTime - info->startPitTime);
175  }
176  } else if ((car->ctrl.raceCmd & RM_CMD_PIT_ASKED) &&
177  car->_pit->pitCarIndex == TR_PIT_STATE_FREE &&
178  (s->_maxDammage == 0 || car->_dammage <= s->_maxDammage))
179  {
180  tdble lgFromStart = car->_trkPos.seg->lgfromstart;
181 
182  switch (car->_trkPos.seg->type) {
183  case TR_STR:
184  lgFromStart += car->_trkPos.toStart;
185  break;
186  default:
187  lgFromStart += car->_trkPos.toStart * car->_trkPos.seg->radius;
188  break;
189  }
190 
191  if ((lgFromStart > car->_pit->lmin) && (lgFromStart < car->_pit->lmax)) {
192  pitok = 0;
193  int side;
194  tdble toBorder;
195  if (ReInfo->track->pits.side == TR_RGT) {
196  side = TR_SIDE_RGT;
197  toBorder = car->_trkPos.toRight;
198  } else {
199  side = TR_SIDE_LFT;
200  toBorder = car->_trkPos.toLeft;
201  }
202 
203  sseg = car->_trkPos.seg->side[side];
204  wseg = RtTrackGetWidth(sseg, car->_trkPos.toStart);
205  if (sseg->side[side]) {
206  sseg = sseg->side[side];
207  wseg += RtTrackGetWidth(sseg, car->_trkPos.toStart);
208  }
209  if (((toBorder + wseg) < (ReInfo->track->pits.width - car->_dimension_y / 2.0)) &&
210  (fabs(car->_speed_x) < 1.0) &&
211  (fabs(car->_speed_y) < 1.0))
212  {
213  pitok = 1;
214  }
215 
216  if (pitok) {
217  car->_state |= RM_CAR_STATE_PIT;
218  car->_nbPitStops++;
219  for (i = 0; i < car->_pit->freeCarIndex; i++) {
220  if (car->_pit->car[i] == car) {
221  car->_pit->pitCarIndex = i;
222  break;
223  }
224  }
225  info->startPitTime = s->currentTime;
226  snprintf(buf, BUFSIZE, "%s in pits", car->_name);
227  ReRaceMsgSet(buf, 5);
229  if (car->robot->rbPitCmd(car->robot->index, car, s) == ROB_PIT_MENU) {
230  // the pit cmd is modified by menu.
231  ReStop();
232  RmPitMenuStart(car, ReInfo, (void*)car, ReUpdtPitCmd);
233  } else {
234  ReUpdtPitTime(car);
235  }
236  }
237  }
238  }
239  }
240 
241  /* Start Line Crossing */
242  if (info->prevTrkPos.seg != car->_trkPos.seg) {
243  if ((info->prevTrkPos.seg->raceInfo & TR_LAST) && (car->_trkPos.seg->raceInfo & TR_START)) {
244  if (info->lapFlag == 0) {
245  if ((car->_state & RM_CAR_STATE_FINISH) == 0) {
246  car->_laps++;
247  car->_remainingLaps--;
248  if (car->_laps > 1) {
249  car->_lastLapTime = s->currentTime - info->sTime;
250  car->_curTime += car->_lastLapTime;
251  if (car->_bestLapTime != 0) {
252  car->_deltaBestLapTime = car->_lastLapTime - car->_bestLapTime;
253  }
254  if ((car->_lastLapTime < car->_bestLapTime) || (car->_bestLapTime == 0)) {
255  if (car->_commitBestLapTime) {
256  car->_bestLapTime = car->_lastLapTime;
257  }
258  }
259 
260  car->_commitBestLapTime = true;
261 
262  if (car->_pos != 1) {
263  car->_timeBehindLeader = car->_curTime - s->cars[0]->_curTime;
264  car->_lapsBehindLeader = s->cars[0]->_laps - car->_laps;
265  car->_timeBehindPrev = car->_curTime - s->cars[car->_pos - 2]->_curTime;
266  s->cars[car->_pos - 2]->_timeBeforeNext = car->_timeBehindPrev;
267  } else {
268  car->_timeBehindLeader = 0;
269  car->_lapsBehindLeader = 0;
270  car->_timeBehindPrev = 0;
271 
272  if (ReInfo->_displayMode == RM_DISP_MODE_CONSOLE) {
273  printf("Sim Time: %8.2f [s], Leader Laps: %4d, Leader Distance: %8.3f [km]\n", s->currentTime, car->_laps - 1, car->_distRaced/1000.0f);
274  }
275  }
276  info->sTime = s->currentTime;
277  switch (ReInfo->s->_raceType) {
278  case RM_TYPE_PRACTICE:
279  if (ReInfo->_displayMode == RM_DISP_MODE_NONE) {
280  ReInfo->_refreshDisplay = 1;
281  const int TIMEFMTSIZE=256;
282  char t1[TIMEFMTSIZE], t2[TIMEFMTSIZE];
283  GfTime2Str(t1, TIMEFMTSIZE, car->_lastLapTime, 0);
284  GfTime2Str(t2, TIMEFMTSIZE, car->_bestLapTime, 0);
285  snprintf(buf, BUFSIZE, "lap: %02d time: %s best: %s top spd: %.2f min spd: %.2f damage: %d",
286  car->_laps - 1, t1, t2,
287  info->topSpd * 3.6, info->botSpd * 3.6, car->_dammage);
288  ReResScreenAddText(buf);
289  }
290  /* save the lap result */
291  ReSavePracticeLap(car);
292  break;
293 
294  case RM_TYPE_QUALIF:
295  if (ReInfo->_displayMode == RM_DISP_MODE_NONE) {
297  }
298  break;
299  }
300  } else {
301  if ((ReInfo->_displayMode == RM_DISP_MODE_NONE) && (ReInfo->s->_raceType == RM_TYPE_QUALIF)) {
303  }
304  }
305 
306  info->topSpd = car->_speed_x;
307  info->botSpd = car->_speed_x;
308  car->_currentMinSpeedForLap = car->_speed_x;
309  if ((car->_remainingLaps < 0) || (s->_raceState == RM_RACE_FINISHING)) {
310  car->_state |= RM_CAR_STATE_FINISH;
311  s->_raceState = RM_RACE_FINISHING;
312  if (ReInfo->s->_raceType == RM_TYPE_RACE) {
313  if (car->_pos == 1) {
314  snprintf(buf, BUFSIZE, "Winner %s", car->_name);
315  ReRaceBigMsgSet(buf, 10);
316  } else {
317  const char *numSuffix = "th";
318  if (abs(12 - car->_pos) > 1) { /* leave suffix as 'th' for 11 to 13 */
319  switch (car->_pos % 10) {
320  case 1:
321  numSuffix = "st";
322  break;
323  case 2:
324  numSuffix = "nd";
325  break;
326  case 3:
327  numSuffix = "rd";
328  break;
329  default:
330  break;
331  }
332  }
333  snprintf(buf, BUFSIZE, "%s Finished %d%s", car->_name, car->_pos, numSuffix);
334  ReRaceMsgSet(buf, 5);
335  }
336  }
337  }
338  } else {
339  /* prevent infinite looping of cars around track, allow one lap after finish for the first car */
340  for (i = 0; i < s->_ncars; i++) {
341  s->cars[i]->_state |= RM_CAR_STATE_FINISH;
342  }
343  return;
344  }
345  } else {
346  info->lapFlag--;
347  }
348  }
349 
350  if ((info->prevTrkPos.seg->raceInfo & TR_START) && (car->_trkPos.seg->raceInfo & TR_LAST)) {
351  /* going backward through the start line */
352  info->lapFlag++;
353  }
354  }
355  ReRaceRules(car);
356 
357  info->prevTrkPos = car->_trkPos;
358  car->_curLapTime = s->currentTime - info->sTime;
359  car->_distFromStartLine = car->_trkPos.seg->lgfromstart +
360  (car->_trkPos.seg->type == TR_STR ? car->_trkPos.toStart : car->_trkPos.toStart * car->_trkPos.seg->radius);
361  car->_distRaced = (car->_laps - (info->lapFlag + 1)) * ReInfo->track->length + car->_distFromStartLine;
362 }
363 
364 
365 static void ReSortCars(void)
366 {
367  int i, j;
368  tCarElt *car;
369  int allfinish;
370  tSituation *s = ReInfo->s;
371 
372  if ((s->cars[0]->_state & RM_CAR_STATE_FINISH) == 0) {
373  allfinish = 0;
374  } else {
375  allfinish = 1;
376  }
377 
378  for (i = 1; i < s->_ncars; i++) {
379  j = i;
380  while (j > 0) {
381  if ((s->cars[j]->_state & RM_CAR_STATE_FINISH) == 0) {
382  allfinish = 0;
383  if (s->cars[j]->_distRaced > s->cars[j-1]->_distRaced) {
384  car = s->cars[j];
385  s->cars[j] = s->cars[j-1];
386  s->cars[j-1] = car;
387  s->cars[j]->_pos = j+1;
388  s->cars[j-1]->_pos = j;
389  j--;
390  continue;
391  }
392  }
393  j = 0;
394  }
395  }
396 
397  if (allfinish) {
398  ReInfo->s->_raceState = RM_RACE_ENDED;
399  }
400 }
401 
402 
403 /* Compute the race rules and penalties */
404 static void
406 {
407  tCarPenalty *penalty;
408  tTrack *track = ReInfo->track;
409  tRmCarRules *rules = &(ReInfo->rules[car->index]);
410  tTrackSeg *seg = RtTrackGetSeg(&(car->_trkPos));
411  tReCarInfo *info = &(ReInfo->_reCarInfo[car->index]);
412  tTrackSeg *prevSeg = RtTrackGetSeg(&(info->prevTrkPos));
413  static float color[] = {0.0, 0.0, 1.0, 1.0};
414 
415  // DNF cars which need too much time for the current lap, this is mainly to avoid
416  // that a "hanging" driver can stop the quali from finishing.
417  // Allowed time is longest pitstop possible + time for tracklength with speed??? (currently fixed 10 [m/s]).
418  // for simplicity. Human driver is an exception to this rule, to allow explorers
419  // to enjoy the landscape.
420  // TODO: Make it configurable.
421  if ((car->_curLapTime > 84.5 + ReInfo->track->length/10.0) &&
422  (car->_driverType != RM_DRV_HUMAN))
423  {
424  car->_state |= RM_CAR_STATE_ELIMINATED;
425  return;
426  }
427 
428  const int BUFSIZE = 1024;
429  char buf[BUFSIZE];
430 
431  // Ignore some rules after the car has finished the race
432  if ((car->pub.state & RM_CAR_STATE_FINISH) == 0) {
433 
434  // If a car hits the track wall the lap time is invalidated, because of tracks where this behaviour allows much faster laps (e.g. alpine-2)
435  // Invalidation and message is just shown on the first hit
437  if (car->_commitBestLapTime && (car->priv.simcollision & SEM_COLLISION_XYSCENE)) {
438  car->_commitBestLapTime = false;
439  if (ReInfo->s->_raceType != RM_TYPE_RACE) {
440  ReRaceMsgSet("Hit wall, laptime invalidated", 5);
441  }
442  }
443  }
444 
445  // If the car cuts a corner the lap time is invalidated. Cutting a corner means: the center of gravity is more than 0.7 times the car width
446  // away from the main track segment on the inside of a turn. The rule does not apply on the outside and on straights, pit entry and exit
447  // count as well as track.
448  tTrackSeg *mainseg = car->_trkPos.seg;
449  bool pit = false;
450  tTrackPitInfo pitInfo = track->pits;
451  tdble toborder = 0.0f;
452  tdble minradius = 1.0f;
453 
454  if (mainseg->type != TR_STR) {
455  if (track->pits.type == TR_PIT_ON_TRACK_SIDE) {
456  if (pitInfo.pitEntry->id < pitInfo.pitExit->id) {
457  if ((mainseg->id >= pitInfo.pitEntry->id) && (mainseg->id <= pitInfo.pitExit->id)) {
458  pit = true;
459  }
460  } else {
461  if ((mainseg->id >= pitInfo.pitEntry->id) || (mainseg->id <= pitInfo.pitExit->id)) {
462  pit = true;
463  }
464  }
465  }
466 
467  if (mainseg->type == TR_LFT) {
468  if (!(pit && (pitInfo.side == TR_LFT))) {
469  toborder = car->_trkPos.toLeft;
470  minradius = mainseg->radiusl;
471  }
472  } else if (mainseg->type == TR_RGT) {
473  if (!(pit && (pitInfo.side == TR_RGT))) {
474  toborder = car->_trkPos.toRight;
475  minradius = mainseg->radiusr;
476  }
477  }
478  }
479 
480  tdble cuttinglimit = car->_dimension_y*0.7f;
481  if (toborder < -cuttinglimit) {
483  if (ReInfo->s->_raceType != RM_TYPE_RACE && car->_commitBestLapTime) {
484  ReRaceMsgSet("Cut corner, laptime invalidated", 5);
485  }
486  car->_commitBestLapTime = false;
487  }
489  // In race, apply additionally corner cutting time penalty
490  minradius -= cuttinglimit;
491  if (minradius > 1.0f) {
492  car->_penaltyTime += car->pub.speed*RCM_MAX_DT_SIMU*(-toborder-cuttinglimit)/minradius;
493  }
494  }
495  }
496  }
497 
498  if (car->_skillLevel < 3) {
499  /* only for the pros */
500  return;
501  }
502 
503  penalty = GF_TAILQ_FIRST(&(car->_penaltyList));
504  if (penalty) {
505  if (car->_laps > penalty->lapToClear) {
506  /* too late to clear the penalty, out of race */
507  car->_state |= RM_CAR_STATE_ELIMINATED;
508  return;
509  }
510 
511  switch (penalty->penalty) {
513  snprintf(car->ctrl.msg[3], 32, "Drive Through Penalty");
514  break;
516  snprintf(car->ctrl.msg[3], 32, "Stop And Go Penalty");
517  break;
518  default:
519  *(car->ctrl.msg[3]) = 0;
520  break;
521  }
522 
523  memcpy(car->ctrl.msgColor, color, sizeof(car->ctrl.msgColor));
524  }
525 
526  if (prevSeg->raceInfo & TR_PITSTART) {
527  /* just entered the pit lane */
528  if (seg->raceInfo & TR_PIT) {
529  /* may be a penalty can be cleaned up */
530  if (penalty) {
531  switch (penalty->penalty) {
533  snprintf(buf, BUFSIZE, "%s DRIVE THROUGH PENALTY CLEANING", car->_name);
534  ReRaceMsgSet(buf, 5);
536  break;
538  snprintf(buf, BUFSIZE, "%s STOP&GO PENALTY CLEANING", car->_name);
539  ReRaceMsgSet(buf, 5);
540  rules->ruleState |= RM_PNST_STOPANDGO;
541  break;
542  }
543  }
544  }
545  } else if (prevSeg->raceInfo & TR_PIT) {
546  if (seg->raceInfo & TR_PIT) {
547  /* the car stopped in pits */
548  if (car->_state & RM_CAR_STATE_PIT) {
549  if (rules->ruleState & RM_PNST_DRIVETHROUGH) {
550  /* it's not more a drive through */
551  rules->ruleState &= ~RM_PNST_DRIVETHROUGH;
552  } else if (rules->ruleState & RM_PNST_STOPANDGO) {
554  }
555  } else {
556  if(rules->ruleState & RM_PNST_STOPANDGO_OK && car->_pitStopType != RM_PIT_STOPANDGO) {
558  }
559  }
560  } else if (seg->raceInfo & TR_PITEND) {
561  /* went out of the pit lane, check if the current penalty is cleared */
563  /* clear the penalty */
564  snprintf(buf, BUFSIZE, "%s penalty cleared", car->_name);
565  ReRaceMsgSet(buf, 5);
566  penalty = GF_TAILQ_FIRST(&(car->_penaltyList));
567  GF_TAILQ_REMOVE(&(car->_penaltyList), penalty, link);
568  FREEZ(penalty);
569  }
570 
571  rules->ruleState = 0;
572  } else {
573  /* went out of the pit lane illegally... */
574  /* it's a new stop and go... */
575  if (!(rules->ruleState & RM_PNST_STNGO)) {
576  snprintf(buf, BUFSIZE, "%s STOP&GO PENALTY", car->_name);
577  ReRaceMsgSet(buf, 5);
578  penalty = (tCarPenalty*)calloc(1, sizeof(tCarPenalty));
579  penalty->penalty = RM_PENALTY_STOPANDGO;
580  penalty->lapToClear = car->_laps + 5;
581  GF_TAILQ_INSERT_TAIL(&(car->_penaltyList), penalty, link);
582  rules->ruleState = RM_PNST_STNGO;
583  }
584  }
585  } else if (seg->raceInfo & TR_PITEND) {
586  rules->ruleState = 0;
587  } else if (seg->raceInfo & TR_PIT) {
588  /* entrered the pits not from the pit entry... */
589  /* it's a new stop and go... */
590  if (!(rules->ruleState & RM_PNST_STNGO)) {
591  snprintf(buf, BUFSIZE, "%s STOP&GO PENALTY", car->_name);
592  ReRaceMsgSet(buf, 5);
593  penalty = (tCarPenalty*)calloc(1, sizeof(tCarPenalty));
594  penalty->penalty = RM_PENALTY_STOPANDGO;
595  penalty->lapToClear = car->_laps + 5;
596  GF_TAILQ_INSERT_TAIL(&(car->_penaltyList), penalty, link);
597  rules->ruleState = RM_PNST_STNGO;
598  }
599  }
600 
601  if (seg->raceInfo & TR_SPEEDLIMIT) {
602  if (!(rules->ruleState & (RM_PNST_SPD | RM_PNST_STNGO)) && (car->_speed_x > track->pits.speedLimit)) {
603  snprintf(buf, BUFSIZE, "%s DRIVE THROUGH PENALTY", car->_name);
604  ReRaceMsgSet(buf, 5);
605  rules->ruleState |= RM_PNST_SPD;
606  penalty = (tCarPenalty*)calloc(1, sizeof(tCarPenalty));
607  penalty->penalty = RM_PENALTY_DRIVETHROUGH;
608  penalty->lapToClear = car->_laps + 5;
609  GF_TAILQ_INSERT_TAIL(&(car->_penaltyList), penalty, link);
610  }
611  }
612 }
613 
614 
615 static void
616 ReOneStep(double deltaTimeIncrement)
617 {
618  int i;
619  tRobotItf *robot;
620  tSituation *s = ReInfo->s;
621 
622  if ((ReInfo->_displayMode != RM_DISP_MODE_NONE) && (ReInfo->_displayMode != RM_DISP_MODE_CONSOLE)) {
623  if (floor(s->currentTime) == -2.0) {
624  ReRaceBigMsgSet("Ready", 1.0);
625  } else if (floor(s->currentTime) == -1.0) {
626  ReRaceBigMsgSet("Set", 1.0);
627  } else if (floor(s->currentTime) == 0.0) {
628  ReRaceBigMsgSet("Go", 1.0);
629  }
630  }
631 
632  ReInfo->_reCurTime += deltaTimeIncrement * ReInfo->_reTimeMult; /* "Real" time */
633  s->currentTime += deltaTimeIncrement; /* Simulated time */
634 
635  if (s->currentTime < 0) {
636  /* no simu yet */
637  ReInfo->s->_raceState = RM_RACE_PRESTART;
638  } else if (ReInfo->s->_raceState == RM_RACE_PRESTART) {
639  ReInfo->s->_raceState = RM_RACE_RUNNING;
640  s->currentTime = 0.0; /* resynchronize */
641  ReInfo->_reLastTime = 0.0;
642  }
643 
644  START_PROFILE("rbDrive*");
645  if ((s->currentTime - ReInfo->_reLastTime) >= RCM_MAX_DT_ROBOTS) {
646  s->deltaTime = s->currentTime - ReInfo->_reLastTime;
647  for (i = 0; i < s->_ncars; i++) {
648  if ((s->cars[i]->_state & RM_CAR_STATE_NO_SIMU) == 0) {
649  robot = s->cars[i]->robot;
650  robot->rbDrive(robot->index, s->cars[i], s);
651  }
652  }
653  ReInfo->_reLastTime = s->currentTime;
654  }
655  STOP_PROFILE("rbDrive*");
656 
657  START_PROFILE("_reSimItf.update*");
658  ReInfo->_reSimItf.update(s, deltaTimeIncrement, -1);
659  for (i = 0; i < s->_ncars; i++) {
660  ReManage(s->cars[i]);
661  }
662  STOP_PROFILE("_reSimItf.update*");
663 
664  if ((ReInfo->_displayMode != RM_DISP_MODE_NONE) && (ReInfo->_displayMode != RM_DISP_MODE_CONSOLE)) {
665  ReRaceMsgUpdate();
666  }
667  ReSortCars();
668 }
669 
670 void
671 ReStart(void)
672 {
673  ReInfo->_reRunning = 1;
674  ReInfo->_reCurTime = GfTimeClock() - RCM_MAX_DT_SIMU;
675 }
676 
677 void
678 ReStop(void)
679 {
680  ReInfo->_reGraphicItf.muteformenu();
681  ReInfo->_reRunning = 0;
682 }
683 
684 static void
686 {
687  unsigned char *img;
688  int sw, sh, vw, vh;
689  tRmMovieCapture *capture = &(ReInfo->movieCapture);
690  const int BUFSIZE = 1024;
691  char buf[BUFSIZE];
692 
693  GfScrGetSize(&sw, &sh, &vw, &vh);
694  img = (unsigned char*)malloc(vw * vh * 3);
695  if (img == NULL) {
696  return;
697  }
698 
699  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
700  glPixelStorei(GL_PACK_ALIGNMENT, 1);
701  glReadBuffer(GL_FRONT);
702  glReadPixels((sw-vw)/2, (sh-vh)/2, vw, vh, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img);
703 
704  snprintf(buf, BUFSIZE, "%s/torcs-%4.4d-%8.8d.png", capture->outputBase, capture->currentCapture, capture->currentFrame++);
705  GfImgWritePng(img, buf, vw, vh);
706  free(img);
707 }
708 
709 
710 int
711 ReUpdate(void)
712 {
713  double t;
714  tRmMovieCapture *capture;
715  int mode = RM_ASYNC;
716  int i;
717  const int MAXSTEPS = 2000;
718 
719  START_PROFILE("ReUpdate");
720  ReInfo->_refreshDisplay = 0;
721  switch (ReInfo->_displayMode) {
722  case RM_DISP_MODE_NORMAL:
723  t = GfTimeClock();
724 
725  i = 0;
726  START_PROFILE("ReOneStep*");
727  while ((ReInfo->_reRunning && ((t - ReInfo->_reCurTime) > RCM_MAX_DT_SIMU)) && MAXSTEPS > i++) {
729  }
730  STOP_PROFILE("ReOneStep*");
731 
732  if (i > MAXSTEPS) {
733  // Cannot keep up with time warp, reset time to avoid lag when running slower again
734  ReInfo->_reCurTime = GfTimeClock();
735  }
736 
737  GfuiDisplay();
738  ReInfo->_reGraphicItf.refresh(ReInfo->s);
739  glutPostRedisplay(); /* Callback -> reDisplay */
740  break;
741 
742  case RM_DISP_MODE_NONE:
743  // Just update view once per 2 seconds simulation time to avoid trouble with graphics cards
744  // which are bad in buffer switching (e.g. ATI fglrx driver on Linux).
745  t = ReInfo->_reCurTime;
746  while ((t - ReInfo->_reCurTime + 2.0) > 0.0) {
748  }
749 
750  GfuiDisplay();
751  glutPostRedisplay(); /* Callback -> reDisplay */
752  break;
753 
755  capture = &(ReInfo->movieCapture);
756  while ((ReInfo->_reCurTime - capture->lastFrame) < capture->deltaFrame) {
757  ReOneStep(capture->deltaSimu);
758  }
759  capture->lastFrame = ReInfo->_reCurTime;
760 
761  GfuiDisplay();
762  ReInfo->_reGraphicItf.refresh(ReInfo->s);
763  reCapture();
764  glutPostRedisplay(); /* Callback -> reDisplay */
765  break;
766 
768  t = ReInfo->_reCurTime;
769  while ((t - ReInfo->_reCurTime + 2.0) > 0.0) {
771  }
772  mode = RM_SYNC;
773  break;
774 
775  }
776  STOP_PROFILE("ReUpdate");
777 
778  return mode;
779 }
780 
781 void
782 ReTimeMod (void *vcmd)
783 {
784  long cmd = (long)vcmd;
785 
786  switch ((int)cmd) {
787  case 0:
788  ReInfo->_reTimeMult *= 2.0;
789  if (ReInfo->_reTimeMult > 64.0) {
790  ReInfo->_reTimeMult = 64.0;
791  }
792  break;
793  case 1:
794  ReInfo->_reTimeMult *= 0.5;
795  if (ReInfo->_reTimeMult < 1.0f/128.0f) {
796  ReInfo->_reTimeMult = 1.0f/128.0f;
797  }
798  break;
799  case 2:
800  default:
801  ReInfo->_reTimeMult = 1.0;
802  break;
803  }
804 
805  const int BUFSIZE = 1024;
806  char buf[BUFSIZE];
807 
808  snprintf(buf, BUFSIZE, "Time x%.2f", 1.0 / ReInfo->_reTimeMult);
809  ReRaceMsgSet(buf, 5);
810 }
#define RM_CMD_PIT_ASKED
Race command: Pit asked.
Definition: car.h:352
tdble topSpd
Definition: raceman.h:123
Race Manager General Info.
Definition: raceman.h:218
void ReSetRaceMsg(const char *msg)
Definition: racegl.cpp:139
tRmCarRules * rules
by car rules
Definition: raceman.h:226
int lapFlag
Definition: raceman.h:119
double currentTime
current time in sec since the beginning of the simulation
Definition: raceman.h:88
tdble refuelFuelFlow
Definition: raceman.h:190
static void ReRaceMsgUpdate(void)
Definition: raceengine.cpp:96
int type
Geometrical type:
Definition: track.h:280
void RtInitCarPitSetup(void *carparmhandle, tCarPitSetup *setup, bool minmaxonly)
Initialize tCarPitSetup from data in parameter set given in handle hdle.
Definition: rttrack.cpp:714
int raceCmd
command issued by the driver
Definition: car.h:350
#define TR_PIT
Car pit.
Definition: track.h:383
tTrackSeg * RtTrackGetSeg(tTrkLocPos *p)
Get the current segment.
Definition: rttrack.cpp:413
int GfImgWritePng(unsigned char *img, const char *filename, int width, int height)
Write a buffer to a png image on disk.
Definition: img.cpp:201
cars situation used to inform the GUI and the drivers
Definition: raceman.h:85
Interface Structure for Robots.
Definition: robot.h:107
tInitCar info
public
Definition: car.h:458
#define RM_TYPE_PRACTICE
Definition: raceman.h:71
#define TR_SPEEDLIMIT
Segment where the speed is limited.
Definition: track.h:380
int ruleState
Definition: raceman.h:199
TireChange tireChange
Definition: car.h:445
#define TR_STR
Straight.
Definition: track.h:287
tCarElt ** cars
list of cars
Definition: raceman.h:90
#define GF_TAILQ_INSERT_TAIL(head, elm, field)
Insert an element at the tail.
Definition: tgf.h:511
tCarCtrl ctrl
private
Definition: car.h:462
#define FREEZ(x)
Definition: tgf.h:60
double lastFrame
Definition: raceman.h:208
static void ReRaceRules(tCarElt *car)
Definition: raceengine.cpp:405
tTrkLocPos prevTrkPos
Definition: raceman.h:117
#define RM_DRV_HUMAN
Definition: car.h:122
int side
Pits side:
Definition: track.h:464
Car structure (tCarElt).
Definition: car.h:455
#define TR_PIT_ON_TRACK_SIDE
The pits are on the track side.
Definition: track.h:460
void RmPitMenuStart(tCarElt *car, tRmInfo *reInfo, void *userdata, tfuiCallback callback)
Pit menu.
Definition: pitmenu.cpp:129
One penalty.
Definition: car.h:130
unsigned int raceInfo
Type of segment regarding the race: Mask value in:
Definition: track.h:365
#define RM_SYNC
Definition: raceman.h:42
double deltaSimu
Definition: raceman.h:206
double deltaFrame
Definition: raceman.h:207
#define RM_RACE_FINISHING
Definition: raceman.h:65
tCarPitCmd pitcmd
private
Definition: car.h:463
Robots Tools.
Track structure.
Definition: track.h:502
Robot Module Interface Definition.
#define RM_PNST_STOPANDGO
Definition: raceman.h:174
void GfuiDisplay(void)
Display function for the GUI to be called during redisplay of glut.
Definition: gui.cpp:136
char msg[4][32]
4 lines of 31 characters 0-1 from car 2-3 from race engine
Definition: car.h:353
tSituation * s
Situation during race.
Definition: raceman.h:221
#define RM_PENALTY_STOPANDGO
Definition: car.h:127
int currentCapture
Definition: raceman.h:210
#define RM_PNST_STOPANDGO_OK
Definition: raceman.h:175
#define TR_SIDE_LFT
Definition: track.h:403
static void ReRaceBigMsgSet(const char *msg, double life)
Definition: raceengine.cpp:117
#define STOP_PROFILE(a)
Definition: tgf.h:598
static double msgDisp
Definition: raceengine.cpp:42
#define RM_CAR_STATE_NO_SIMU
Do not simulate the car.
Definition: car.h:217
#define START_PROFILE(a)
Definition: tgf.h:597
tTrackSeg * pitEntry
Pit lane segment.
Definition: track.h:471
The Gaming Framework API (client part).
int simcollision
For rules etc.
Definition: car.h:307
#define RCM_MAX_DT_ROBOTS
Definition: raceman.h:57
double startPitTime
Definition: raceman.h:122
#define RM_PNST_SPD
Definition: raceman.h:176
tdble length
main track length
Definition: track.h:512
#define RM_PNST_DRIVETHROUGH
Definition: raceman.h:173
static void reCapture(void)
Definition: raceengine.cpp:685
#define RM_TYPE_QUALIF
Definition: raceman.h:72
tRmInfo * ReInfo
Definition: raceengine.cpp:45
#define TR_LAST
Segment before start line.
Definition: track.h:377
#define RM_PNST_STNGO
Definition: raceman.h:177
tdble sTime
Definition: raceman.h:118
#define TR_LFT
Left curve.
Definition: track.h:286
void ReSetRaceBigMsg(const char *msg)
Definition: racegl.cpp:155
tdble radiusr
Radius in meters of the right side of the track (>0)
Definition: track.h:321
float tdble
Floating point type used in TORCS.
Definition: tgf.h:48
double totalPitTime
Definition: raceman.h:121
int currentFrame
Definition: raceman.h:211
struct RobotItf * robot
private
Definition: car.h:464
int ReUpdate(void)
Definition: raceengine.cpp:711
tdble radiusl
Radius in meters of the left side of the track (>0)
Definition: track.h:322
void ReStart(void)
Definition: raceengine.cpp:671
#define RM_DISP_MODE_NONE
Definition: raceman.h:148
tdble pitstopBaseTime
Definition: raceman.h:192
#define RM_DISP_MODE_CAPTURE
Definition: raceman.h:147
struct trackSeg * side[2]
Definition: track.h:407
static double bigMsgDisp
Definition: raceengine.cpp:43
tCarPitSetup setup
Definition: car.h:441
tTrack * track
Current track.
Definition: raceman.h:222
tRmRaceRules raceRules
Definition: raceman.h:229
tPublicCar pub
public
Definition: car.h:459
#define TR_PITEND
Car pit End.
Definition: track.h:385
#define RM_PENALTY_DRIVETHROUGH
Definition: car.h:126
#define RM_PIT_REPAIR
Definition: car.h:438
tTrackSeg * pitExit
Pit lane segment.
Definition: track.h:474
static void ReSortCars(void)
Definition: raceengine.cpp:365
void ReTimeMod(void *vcmd)
Definition: raceengine.cpp:782
#define RM_TYPE_RACE
Definition: raceman.h:73
tPrivCar priv
private
Definition: car.h:461
tRmMovieCapture movieCapture
Definition: raceman.h:228
void ReSavePracticeLap(tCarElt *car)
tdble allTiresChangeTime
Definition: raceman.h:194
This is the race information structures.
#define RM_RACE_RUNNING
Definition: raceman.h:64
int index
car index
Definition: car.h:457
int enabled
Definition: raceman.h:187
#define RM_RACE_PRESTART
Definition: raceman.h:68
void GfuiScreenActivate(void *screen)
Activate a screen and make it current.
Definition: gui.cpp:467
void ReResScreenAddText(char *text)
Definition: racegl.cpp:366
static void ReUpdtPitTime(tCarElt *car)
Definition: raceengine.cpp:52
tfRbDrive rbDrive
Definition: robot.h:111
#define RM_PIT_STOPANDGO
Definition: car.h:439
#define GF_TAILQ_FIRST(head)
First element of a TAILQ.
Definition: tgf.h:464
static void ReManage(tCarElt *car)
Definition: raceengine.cpp:127
#define TR_SIDE_RGT
Definition: track.h:404
tdble tireFactor
Definition: raceman.h:193
tTrackSeg * seg
Track segment.
Definition: track.h:420
void GfScrGetSize(int *scrw, int *scrh, int *vieww, int *viewh)
Get the screen and viewport sizes.
Definition: screen.cpp:471
double GfTimeClock(void)
Get the time in seconds.
Definition: os.cpp:50
tdble width
Width of each pit stop.
Definition: track.h:469
tdble RtTrackGetWidth(tTrackSeg *seg, tdble toStart)
Get the track width at the specified point.
Definition: rttrack.cpp:58
static void ReRaceMsgSet(const char *msg, double life)
Definition: raceengine.cpp:107
#define GF_TAILQ_REMOVE(head, elm, field)
Remove an element.
Definition: tgf.h:541
int type
Race type.
Definition: raceman.h:70
Track segment (tTrackSeg) The segments can be straights (type TR_STR): (the track goes from the right...
Definition: track.h:276
tRaceAdmInfo raceInfo
Definition: raceman.h:86
int track(tModInfo *modInfo)
Definition: trackitf.cpp:85
void ReStop(void)
Definition: raceengine.cpp:678
#define RM_CAR_STATE_ELIMINATED
Eliminated due to rules infringement.
Definition: car.h:220
Pits Info Structure.
Definition: track.h:453
#define RM_CAR_STATE_PIT
Car currently stopped in pits.
Definition: car.h:211
#define TR_START
Segment after start line.
Definition: track.h:378
#define ROB_PIT_MENU
Call the interactive menu for pit command.
Definition: robot.h:101
#define _pit
Definition: car.h:184
#define RM_RACE_ENDED
Definition: raceman.h:66
#define TR_RGT
Right curve.
Definition: track.h:285
tdble speed
Definition: car.h:194
int lapToClear
the lap before the penalty has to be cleared
Definition: car.h:133
#define TR_PIT_STATE_FREE
Definition: track.h:444
#define RM_DISP_MODE_CONSOLE
Definition: raceman.h:149
int penalty
penalty type
Definition: car.h:132
void GfTime2Str(char *result, int resultSize, tdble sec, int sgn)
Convert a time in seconds (float) to an ascii string.
Definition: tgf.cpp:193
tfRbPitCmd rbPitCmd
Definition: robot.h:112
#define RM_ASYNC
Definition: raceman.h:43
static void ReOneStep(double deltaTimeIncrement)
Definition: raceengine.cpp:616
void ReUpdateQualifCurRes(tCarElt *car)
Race Engine Car Information about the race.
Definition: raceman.h:115
#define RM_DISP_MODE_NORMAL
Definition: raceman.h:146
tdble damageRepairFactor
Definition: raceman.h:191
#define SEM_COLLISION_XYSCENE
Definition: car.h:691
float msgColor[4]
RGBA of text.
Definition: car.h:355
int skillLevel
Driver&#39;s skill level (0=rookie -> 3=pro)
Definition: car.h:81
int index
Definition: robot.h:114
double deltaTime
Definition: raceman.h:87
tTrackPitInfo pits
Pits information.
Definition: track.h:514
#define RCM_MAX_DT_SIMU
Definition: raceman.h:56
int id
Segment number.
Definition: track.h:278
int state
state of the car.
Definition: car.h:197
#define TR_PITSTART
Car pit Star.
Definition: track.h:384
const char * outputBase
Definition: raceman.h:209
#define RM_CAR_STATE_FINISH
Car having passed the finish line.
Definition: car.h:210
static void ReUpdtPitCmd(void *pvcar)
Definition: raceengine.cpp:87
tdble botSpd
Definition: raceman.h:124