/***************************************************************************
file : tutorial5.cpp
created : September 2026
copyright : (C) 2026 by Bernhard Wymann
email : berniw@bluewin.ch
***************************************************************************/
/* This program is free software; you can redistribute it and/or modify it
* under the GNU General Public License, version 2 or (at your option) any
* later version. Distributed WITHOUT ANY WARRANTY, including MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See .
*/
#include
#include
#include
#include
#include "recovery4.h"
#include "traffic5.h"
static tTrack* currentTrack = nullptr;
static SpeedDriver driver;
static Recovery recovery;
static TrafficPlanner traffic;
static void
initTrack(int, tTrack* track, void*, void** settings, tSituation*)
{
currentTrack = track;
*settings = nullptr;
}
static void
newRace(int, tCarElt* car, tSituation* situation)
{
driver.configure(currentTrack, car);
recovery.reset(situation->currentTime);
traffic.reset(situation->currentTime);
}
static void
drive(int, tCarElt* car, tSituation* situation)
{
traffic.observe(car, situation, driver.trackLength);
if (traffic.nearby) {
double angle = RtTrackSideTgAngleL(&car->_trkPos) - car->_yaw;
NORM_PI_PI(angle);
if (recovery.mode != Recovery::Mode::Driving ||
(std::fabs(angle) > 0.3 && std::hypot(car->_speed_x, car->_speed_y) < 1.0)) {
// Pause an awkward recovery while another car occupies nearby space.
recovery.previousTime = situation->currentTime;
traffic.previousTime = situation->currentTime;
car->ctrl = tCarCtrl{};
car->ctrl.gear = car->_gear;
car->ctrl.brakeCmd = 1.0f;
return;
}
recovery.reset(situation->currentTime); // Waiting in traffic is not a stuck timer.
} else if (recovery.driveIfNeeded(car, situation)) {
driver.resumeAfterRecovery(situation->currentTime);
traffic.reset(situation->currentTime);
return;
}
traffic.drive(driver, car, situation);
}
static void
shutdown(int)
{
currentTrack = nullptr;
traffic.reset(0.0);
}
static int
initInterface(int index, void* pointer)
{
auto* itf = static_cast(pointer);
*itf = tRobotItf{};
itf->rbNewTrack = initTrack;
itf->rbNewRace = newRace;
itf->rbDrive = drive;
itf->rbShutdown = shutdown;
itf->index = index;
return 0;
}
extern "C" int
tutorial5(tModInfo* modInfo)
{
for (int i = 0; i < 10; ++i) {
modInfo[i] = tModInfo{};
}
modInfo[0].name = strdup("Tutorial 5");
modInfo[0].desc = strdup("Following and overtaking");
modInfo[0].fctInit = initInterface;
modInfo[0].gfId = ROB_IDENT;
modInfo[0].index = 1;
return 0;
}