void
ReTimeMod (void *vcmd)
{
    long cmd = (long)vcmd;
    
    switch ((int)cmd) {
    case 0:
	ReInfo->_reTimeMult *= 2.0;
	if (ReInfo->_reTimeMult > 64.0) {
	    ReInfo->_reTimeMult = 64.0;
	}
	break;
    case 1:
	ReInfo->_reTimeMult *= 0.5;
	if (ReInfo->_reTimeMult < 0.25) {
	    ReInfo->_reTimeMult = 0.25;
	}
	break;
    case 2:
    default:
	ReInfo->_reTimeMult = 1.0;
	break;
    }
    sprintf(buf, "Time x%.2f", 1.0 / ReInfo->_reTimeMult);
    ReRaceMsgSet(buf, 5);
}
Beispiel #2
0
void ReSituation::setRaceMessage(const std::string& strMsg, double fLifeTime, bool bBig)
{
	lock("setRaceMessage");

	if (bBig)
		ReRaceMsgSetBig(_pReInfo, strMsg.c_str(), fLifeTime);
	else
		ReRaceMsgSet(_pReInfo, strMsg.c_str(), fLifeTime);
	
	unlock("setRaceMessage");
}
Beispiel #3
0
void ReSituation::accelerateTime(double fMultFactor)
{
	lock("accelerateTime");

	_pReInfo->_reTimeMult *= fMultFactor;
	if (fMultFactor == 0.0)
	    _pReInfo->_reTimeMult = 1.0;
	else if (_pReInfo->_reTimeMult > 64.0)
	    _pReInfo->_reTimeMult = 64.0;
	else if (_pReInfo->_reTimeMult < 0.0625)
	    _pReInfo->_reTimeMult = 0.0625;

	std::ostringstream ossTimeMult;
	ossTimeMult << "Time x" << std::setprecision(2) << 1.0 / _pReInfo->_reTimeMult;
    ReRaceMsgSet(_pReInfo, ossTimeMult.str().c_str(), 5);

	unlock("accelerateTime");
}
/* Compute the race rules and penalties */
static void
ReRaceRules(tCarElt *car)
{
    tCarPenalty		*penalty;
    tTrack		*track = ReInfo->track;
    tRmCarRules		*rules = &(ReInfo->rules[car->index]);
    tTrackSeg		*seg = RtTrackGetSeg(&(car->_trkPos));
    tReCarInfo		*info = &(ReInfo->_reCarInfo[car->index]);
    tTrackSeg		*prevSeg = RtTrackGetSeg(&(info->prevTrkPos));
    static float	color[] = {0.0, 0.0, 1.0, 1.0};

	// DNF cars which need too much time for the current lap, this is mainly to avoid
	// that a "hanging" driver can stop the quali from finishing.
	// Allowed time is longest pitstop possible + time for tracklength with speed??? (currently fixed 10 [m/s]).
	// for simplicity. Human driver is an exception to this rule, to allow explorers
	// to enjoy the landscape.
	// TODO: Make it configurable.
	if ((car->_curLapTime > 84.5 + ReInfo->track->length/10.0) &&
		(car->_driverType != RM_DRV_HUMAN))
	{
		car->_state |= RM_CAR_STATE_ELIMINATED;
	    return;
	}

	if (car->_skillLevel < 3) {
	/* only for the pros */
	return;
    }

	penalty = GF_TAILQ_FIRST(&(car->_penaltyList));
    if (penalty) {
	if (car->_laps > penalty->lapToClear) {
	    /* too late to clear the penalty, out of race */
	    car->_state |= RM_CAR_STATE_ELIMINATED;
	    return;
	}
	switch (penalty->penalty) {
	case RM_PENALTY_DRIVETHROUGH:
	    sprintf(car->ctrl.msg[3], "Drive Through Penalty");
	    break;
	case RM_PENALTY_STOPANDGO:
	    sprintf(car->ctrl.msg[3], "Stop And Go Penalty");
	    break;
	default:
	    *(car->ctrl.msg[3]) = 0;
	    break;
	}
	memcpy(car->ctrl.msgColor, color, sizeof(car->ctrl.msgColor));
    }
    

    if (prevSeg->raceInfo & TR_PITSTART) {
	/* just entered the pit lane */
	if (seg->raceInfo & TR_PIT) {
	    /* may be a penalty can be cleaned up */
	    if (penalty) {
		switch (penalty->penalty) {
		case RM_PENALTY_DRIVETHROUGH:
		    sprintf(buf, "%s DRIVE THROUGH PENALTY CLEANING", car->_name);
		    ReRaceMsgSet(buf, 5);
		    rules->ruleState |= RM_PNST_DRIVETHROUGH;
		    break;
		case RM_PENALTY_STOPANDGO:
		    sprintf(buf, "%s STOP&GO PENALTY CLEANING", car->_name);
		    ReRaceMsgSet(buf, 5);
		    rules->ruleState |= RM_PNST_STOPANDGO;
		    break;
		}
	    }
	}
    } else if (prevSeg->raceInfo & TR_PIT) {
	if (seg->raceInfo & TR_PIT) {
	    /* the car stopped in pits */
	    if (car->_state & RM_CAR_STATE_PIT) {
		if (rules->ruleState & RM_PNST_DRIVETHROUGH) {
		    /* it's not more a drive through */
		    rules->ruleState &= ~RM_PNST_DRIVETHROUGH;
		} else if (rules->ruleState & RM_PNST_STOPANDGO) {
		    rules->ruleState |= RM_PNST_STOPANDGO_OK;
		}
	    } else {
                if(rules->ruleState & RM_PNST_STOPANDGO_OK && car->_pitStopType != RM_PIT_STOPANDGO) {
		    rules->ruleState &= ~ ( RM_PNST_STOPANDGO | RM_PNST_STOPANDGO_OK );
		}
	    }
	} else if (seg->raceInfo & TR_PITEND) {
	    /* went out of the pit lane, check if the current penalty is cleared */
	    if (rules->ruleState & (RM_PNST_DRIVETHROUGH | RM_PNST_STOPANDGO_OK)) {
		/* clear the penalty */
		sprintf(buf, "%s penalty cleared", car->_name);
		ReRaceMsgSet(buf, 5);
		penalty = GF_TAILQ_FIRST(&(car->_penaltyList));
		GF_TAILQ_REMOVE(&(car->_penaltyList), penalty, link);
		FREEZ(penalty);
	    }
	    rules->ruleState = 0;
	} else {
	    /* went out of the pit lane illegally... */
	    /* it's a new stop and go... */
	    if (!(rules->ruleState & RM_PNST_STNGO)) {
		sprintf(buf, "%s STOP&GO PENALTY", car->_name);
		ReRaceMsgSet(buf, 5);
		penalty = (tCarPenalty*)calloc(1, sizeof(tCarPenalty));
		penalty->penalty = RM_PENALTY_STOPANDGO;
		penalty->lapToClear = car->_laps + 5;
		GF_TAILQ_INSERT_TAIL(&(car->_penaltyList), penalty, link);
		rules->ruleState = RM_PNST_STNGO;
	    }
	}
    } else if (seg->raceInfo & TR_PITEND) {
	rules->ruleState = 0;
    } else if (seg->raceInfo & TR_PIT) {
	/* entrered the pits not from the pit entry... */
	/* it's a new stop and go... */
	if (!(rules->ruleState & RM_PNST_STNGO)) {
	    sprintf(buf, "%s STOP&GO PENALTY", car->_name);
	    ReRaceMsgSet(buf, 5);
	    penalty = (tCarPenalty*)calloc(1, sizeof(tCarPenalty));
	    penalty->penalty = RM_PENALTY_STOPANDGO;
	    penalty->lapToClear = car->_laps + 5;
	    GF_TAILQ_INSERT_TAIL(&(car->_penaltyList), penalty, link);
	    rules->ruleState = RM_PNST_STNGO;
	}
    }

    if (seg->raceInfo & TR_SPEEDLIMIT) {
	if (!(rules->ruleState & (RM_PNST_SPD | RM_PNST_STNGO)) && (car->_speed_x > track->pits.speedLimit)) {
	    sprintf(buf, "%s DRIVE THROUGH PENALTY", car->_name);
	    ReRaceMsgSet(buf, 5);
	    rules->ruleState |= RM_PNST_SPD;
	    penalty = (tCarPenalty*)calloc(1, sizeof(tCarPenalty));
	    penalty->penalty = RM_PENALTY_DRIVETHROUGH;
	    penalty->lapToClear = car->_laps + 5;
	    GF_TAILQ_INSERT_TAIL(&(car->_penaltyList), penalty, link);
	}
    }


}
static void
ReManage(tCarElt *car)
{
	int i, pitok;
	tTrackSeg *sseg;
	tdble wseg;
	static float color[] = {0.0, 0.0, 1.0, 1.0};
	tSituation *s = ReInfo->s;
	
	tReCarInfo *info = &(ReInfo->_reCarInfo[car->index]);
	
	if (car->_speed_x > car->_topSpeed) {
		car->_topSpeed = car->_speed_x;
	}

	// For practice and qualif.
	if (car->_speed_x > info->topSpd) {
		info->topSpd = car->_speed_x;
	}
	if (car->_speed_x < info->botSpd) {
		info->botSpd = car->_speed_x;
	}
	
	// Pitstop.
	if (car->_pit) {
		if (car->ctrl.raceCmd & RM_CMD_PIT_ASKED) {
			// Pit already occupied?
			if (car->_pit->pitCarIndex == TR_PIT_STATE_FREE) {
				sprintf(car->ctrl.msg[2], "Can Pit");
			} else {
				sprintf(car->ctrl.msg[2], "Pit Occupied");
			}
			memcpy(car->ctrl.msgColor, color, sizeof(car->ctrl.msgColor));
		}
		
		if (car->_state & RM_CAR_STATE_PIT) {
			car->ctrl.raceCmd &= ~RM_CMD_PIT_ASKED; // clear the flag.
			if (car->_scheduledEventTime < s->currentTime) {
				car->_state &= ~RM_CAR_STATE_PIT;
				car->_pit->pitCarIndex = TR_PIT_STATE_FREE;
				sprintf(buf, "%s pit stop %.1fs", car->_name, info->totalPitTime);
				ReRaceMsgSet(buf, 5);
			} else {
				sprintf(car->ctrl.msg[2], "in pits %.1fs", s->currentTime - info->startPitTime);
			}
		} else if ((car->ctrl.raceCmd & RM_CMD_PIT_ASKED) &&
					car->_pit->pitCarIndex == TR_PIT_STATE_FREE &&	
				   (s->_maxDammage == 0 || car->_dammage <= s->_maxDammage))
		{
			tdble lgFromStart = car->_trkPos.seg->lgfromstart;
			
			switch (car->_trkPos.seg->type) {
				case TR_STR:
					lgFromStart += car->_trkPos.toStart;
					break;
				default:
					lgFromStart += car->_trkPos.toStart * car->_trkPos.seg->radius;
					break;
			}
		
			if ((lgFromStart > car->_pit->lmin) && (lgFromStart < car->_pit->lmax)) {
				pitok = 0;
				int side;
				tdble toBorder;
				if (ReInfo->track->pits.side == TR_RGT) {
					side = TR_SIDE_RGT;
					toBorder = car->_trkPos.toRight;
				} else {
					side = TR_SIDE_LFT;
					toBorder = car->_trkPos.toLeft;
				}
				
				sseg = car->_trkPos.seg->side[side];
				wseg = RtTrackGetWidth(sseg, car->_trkPos.toStart);
				if (sseg->side[side]) {
					sseg = sseg->side[side];
					wseg += RtTrackGetWidth(sseg, car->_trkPos.toStart);
				}
				if (((toBorder + wseg) < (ReInfo->track->pits.width - car->_dimension_y / 2.0)) &&
					(fabs(car->_speed_x) < 1.0) &&
					(fabs(car->_speed_y) < 1.0))
				{
					pitok = 1;
				}
				
				if (pitok) {
					car->_state |= RM_CAR_STATE_PIT;
					car->_nbPitStops++;
					for (i = 0; i < car->_pit->freeCarIndex; i++) {
						if (car->_pit->car[i] == car) {
							car->_pit->pitCarIndex = i;
							break;
						}
					}
					info->startPitTime = s->currentTime;
					sprintf(buf, "%s in pits", car->_name);
					ReRaceMsgSet(buf, 5);
					if (car->robot->rbPitCmd(car->robot->index, car, s) == ROB_PIT_MENU) {
						// the pit cmd is modified by menu.
						ReStop();
						RmPitMenuStart(car, (void*)car, ReUpdtPitCmd);
					} else {
						ReUpdtPitTime(car);
					}
				}
			}
		}
	}
	
	/* Start Line Crossing */
	if (info->prevTrkPos.seg != car->_trkPos.seg) {
	if ((info->prevTrkPos.seg->raceInfo & TR_LAST) && (car->_trkPos.seg->raceInfo & TR_START)) {
		if (info->lapFlag == 0) {
		if ((car->_state & RM_CAR_STATE_FINISH) == 0) {
			car->_laps++;
			car->_remainingLaps--;
			if (car->_laps > 1) {
			car->_lastLapTime = s->currentTime - info->sTime;
			car->_curTime += car->_lastLapTime;
			if (car->_bestLapTime != 0) {
				car->_deltaBestLapTime = car->_lastLapTime - car->_bestLapTime;
			}
			if ((car->_lastLapTime < car->_bestLapTime) || (car->_bestLapTime == 0)) {
				car->_bestLapTime = car->_lastLapTime;
			}
			if (car->_pos != 1) {
				car->_timeBehindLeader = car->_curTime - s->cars[0]->_curTime;
				car->_lapsBehindLeader = s->cars[0]->_laps - car->_laps;
				car->_timeBehindPrev = car->_curTime - s->cars[car->_pos - 2]->_curTime;
				s->cars[car->_pos - 2]->_timeBeforeNext = car->_timeBehindPrev;
			} else {
				car->_timeBehindLeader = 0;
				car->_lapsBehindLeader = 0;
				car->_timeBehindPrev = 0;
			}
			info->sTime = s->currentTime;
			switch (ReInfo->s->_raceType) {
			case RM_TYPE_PRACTICE:
				if (ReInfo->_displayMode == RM_DISP_MODE_NONE) {
				ReInfo->_refreshDisplay = 1;
				char *t1, *t2;
				t1 = GfTime2Str(car->_lastLapTime, 0);
				t2 = GfTime2Str(car->_bestLapTime, 0);
				sprintf(buf,"lap: %02d   time: %s  best: %s  top spd: %.2f    min spd: %.2f    damage: %d",
					car->_laps - 1, t1, t2,
					info->topSpd * 3.6, info->botSpd * 3.6, car->_dammage);
				ReResScreenAddText(buf);
				free(t1);
				free(t2);
				}
				/* save the lap result */
				ReSavePracticeLap(car);
				break;
				
			case RM_TYPE_QUALIF:
				if (ReInfo->_displayMode == RM_DISP_MODE_NONE) {
				ReUpdateQualifCurRes(car);
				}
				break;
			}
			} else {
			if ((ReInfo->_displayMode == RM_DISP_MODE_NONE) && (ReInfo->s->_raceType == RM_TYPE_QUALIF)) {
				ReUpdateQualifCurRes(car);
			}
			}
	
			info->topSpd = car->_speed_x;
			info->botSpd = car->_speed_x;
			if ((car->_remainingLaps < 0) || (s->_raceState == RM_RACE_FINISHING)) {
			car->_state |= RM_CAR_STATE_FINISH;
			s->_raceState = RM_RACE_FINISHING;
			if (ReInfo->s->_raceType == RM_TYPE_RACE) {
				if (car->_pos == 1) {
				sprintf(buf, "Winner %s", car->_name);
				ReRaceBigMsgSet(buf, 10);
				} else {
				const char *numSuffix = "th";
				if (abs(12 - car->_pos) > 1) { /* leave suffix as 'th' for 11 to 13 */
					switch (car->_pos % 10) {
					case 1:
					numSuffix = "st";
					break;
					case 2:
					numSuffix = "nd";
					break;
					case 3:
					numSuffix = "rd";
					break;
					default:
					break;
					}
				}
				sprintf(buf, "%s Finished %d%s", car->_name, car->_pos, numSuffix);
				ReRaceMsgSet(buf, 5);
				}
			}
			}
		} else {
			/* prevent infinite looping of cars around track, allow one lap after finish for the first car */
			for (i = 0; i < s->_ncars; i++) {
				s->cars[i]->_state |= RM_CAR_STATE_FINISH;
			}
			return;
		}
		} else {
		info->lapFlag--;
		}
	}
	if ((info->prevTrkPos.seg->raceInfo & TR_START) && (car->_trkPos.seg->raceInfo & TR_LAST)) {
		/* going backward through the start line */
		info->lapFlag++;
	}
	}
	ReRaceRules(car);
	
	info->prevTrkPos = car->_trkPos;
	car->_curLapTime = s->currentTime - info->sTime;
	car->_distFromStartLine = car->_trkPos.seg->lgfromstart +
	(car->_trkPos.seg->type == TR_STR ? car->_trkPos.toStart : car->_trkPos.toStart * car->_trkPos.seg->radius);
	car->_distRaced = (car->_laps - 1) * ReInfo->track->length + car->_distFromStartLine;
}