/*************************************************************************** file : human.cpp created : Sat Mar 18 23:16:38 CET 2000 copyright : (C) 2000 by Eric Espie email : torcs@free.fr version : $Id: human.cpp,v 1.45 2006/09/06 23:46:45 berniw Exp $ ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /** @file @author Eric Espie @version $Id: human.cpp,v 1.45 2006/09/06 23:46:45 berniw Exp $ */ #ifdef _WIN32 #include #define isnan _isnan #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "pref.h" #include "human.h" static void initTrack(int index, tTrack* track, void *carHandle, void **carParmHandle, tSituation *s); static void drive_mt(int index, tCarElt* car, tSituation *s); static void drive_at(int index, tCarElt* car, tSituation *s); static void newrace(int index, tCarElt* car, tSituation *s); static int pitcmd(int index, tCarElt* car, tSituation *s); int joyPresent = 0; static char sstring[1024]; static char buf[1024]; static tTrack *curTrack; //static void *DrvInfo; static float color[] = {0.0, 0.0, 1.0, 1.0}; static tCtrlJoyInfo *joyInfo = NULL; static tCtrlMouseInfo *mouseInfo = NULL; static int masterPlayer = -1; tHumanContext *HCtx[10] = {0}; static int speedLimiter = 0; static tdble Vtarget; typedef struct { int state; int edgeDn; int edgeUp; } tKeyInfo; static tKeyInfo keyInfo[256]; static tKeyInfo skeyInfo[256]; static int currentKey[256]; static int currentSKey[256]; static double lastKeyUpdate = -10.0; static int firstTime = 0; #ifdef _WIN32 /* should be present in mswindows */ BOOL WINAPI DllEntryPoint (HINSTANCE hDLL, DWORD dwReason, LPVOID Reserved) { return TRUE; } #endif static void shutdown(int index) { //static int firstTime = 1; int idx = index - 1; free (HCtx[idx]); if (firstTime) { //GfParmReleaseHandle(DrvInfo); GfParmReleaseHandle(PrefHdle); GfctrlJoyRelease(joyInfo); GfctrlMouseRelease(mouseInfo); GfuiKeyEventRegisterCurrent(NULL); GfuiSKeyEventRegisterCurrent(NULL); firstTime = 0; } } /* * Function * InitFuncPt * * Description * Robot functions initialisation * * Parameters * pt pointer on functions structure * * Return * 0 * * Remarks * */ static int InitFuncPt(int index, void *pt) { tRobotItf *itf = (tRobotItf *)pt; int idx = index - 1; if (masterPlayer == -1) { masterPlayer = index; } if (firstTime < 1) { firstTime = 1; //DrvInfo = GfParmReadFile(buf, GFPARM_RMODE_REREAD | GFPARM_RMODE_CREAT); joyInfo = GfctrlJoyInit(); if (joyInfo) { joyPresent = 1; } mouseInfo = GfctrlMouseInit(); } /* Allocate a new context for that player */ HCtx[idx] = (tHumanContext *) calloc (1, sizeof (tHumanContext)); HCtx[idx]->ABS = 1.0; HCtx[idx]->AntiSlip = 1.0; itf->rbNewTrack = initTrack; /* give the robot the track view called */ /* for every track change or new race */ itf->rbNewRace = newrace; HmReadPrefs(index); if (HCtx[idx]->Transmission == 0) { itf->rbDrive = drive_at; } else { itf->rbDrive = drive_mt; /* drive during race */ } itf->rbShutdown = shutdown; itf->rbPitCmd = pitcmd; itf->index = index; return 0; } /* * Function * human * * Description * DLL entry point (general to all types of modules) * * Parameters * modInfo administrative info on module * * Return * 0 * * Remarks * */ #define MAXNAMELEN 100 static char names[10][MAXNAMELEN]; extern "C" int human(tModInfo *modInfo) { int i; char *driver; memset(modInfo, 0, 10*sizeof(tModInfo)); sprintf(buf, "%sdrivers/human/human.xml", GetLocalDir()); void *DrvInfo = GfParmReadFile(buf, GFPARM_RMODE_REREAD | GFPARM_RMODE_CREAT); if (DrvInfo != NULL) { for (i = 0; i < 10; i++) { sprintf(sstring, "Robots/index/%d", i+1); driver = GfParmGetStr(DrvInfo, sstring, "name", ""); if (strlen(driver) == 0) { break; } strncpy(names[i], driver, MAXNAMELEN); modInfo->name = names[i]; /* name of the module (short) */ //modInfo->name = driver; /* name of the module (short) */ modInfo->desc = "Joystick controlable driver"; /* description of the module (can be long) */ modInfo->fctInit = InitFuncPt; /* init function */ modInfo->gfId = ROB_IDENT; /* supported framework version */ modInfo->index = i+1; modInfo++; } // Just release in case we got it. GfParmReleaseHandle(DrvInfo); } return 0; } /* * Function * * * Description * search under drivers/human/tracks//car--.xml * drivers/human/car--.xml * drivers/human/tracks//car-.xml * drivers/human/car-.xml * * Parameters * * * Return * * * Remarks * */ static void initTrack(int index, tTrack* track, void *carHandle, void **carParmHandle, tSituation *s) { char *carname; char *s1, *s2; char trackname[256]; tdble fuel; int idx = index - 1; curTrack = track; s1 = strrchr(track->filename, '/') + 1; s2 = strchr(s1, '.'); strncpy(trackname, s1, s2-s1); trackname[s2-s1] = 0; sprintf(sstring, "Robots/index/%d", index); sprintf(buf, "%sdrivers/human/human.xml", GetLocalDir()); void *DrvInfo = GfParmReadFile(buf, GFPARM_RMODE_REREAD | GFPARM_RMODE_CREAT); carname = ""; if (DrvInfo != NULL) { carname = GfParmGetStr(DrvInfo, sstring, "car name", ""); } sprintf(sstring, "%sdrivers/human/tracks/%s/car-%s-%d.xml", GetLocalDir(), trackname, carname, index); *carParmHandle = GfParmReadFile(sstring, GFPARM_RMODE_REREAD); if (*carParmHandle != NULL) { GfOut("Player: %s Loaded\n", sstring); } else { sprintf(sstring, "%sdrivers/human/tracks/%s/car-%s.xml", GetLocalDir(), trackname, carname); *carParmHandle = GfParmReadFile(sstring, GFPARM_RMODE_REREAD); if (*carParmHandle != NULL) { GfOut("Player: %s Loaded\n", sstring); } else { sprintf(sstring, "%sdrivers/human/car-%s-%d.xml", GetLocalDir(), carname, index); *carParmHandle = GfParmReadFile(sstring, GFPARM_RMODE_REREAD); if (*carParmHandle != NULL) { GfOut("Player: %s Loaded\n", sstring); } else { sprintf(sstring, "%sdrivers/human/car-%s.xml", GetLocalDir(), carname); *carParmHandle = GfParmReadFile(sstring, GFPARM_RMODE_REREAD); if (*carParmHandle != NULL) { GfOut("Player: %s Loaded\n", sstring); } else { sprintf(sstring, "%sdrivers/human/car.xml", GetLocalDir ()); *carParmHandle = GfParmReadFile(sstring, GFPARM_RMODE_REREAD); if (*carParmHandle != NULL) { GfOut("Player: %s Loaded\n", sstring); } } } } } if (curTrack->pits.type != TR_PIT_NONE) { sprintf(sstring, "%s/%s/%d", HM_SECT_PREF, HM_LIST_DRV, index); HCtx[idx]->NbPitStopProg = (int)GfParmGetNum(PrefHdle, sstring, HM_ATT_NBPITS, (char*)NULL, 0); GfOut("Player: index %d , Pits stops %d\n", index, HCtx[idx]->NbPitStopProg); } else { HCtx[idx]->NbPitStopProg = 0; } fuel = 0.0008 * curTrack->length * (s->_totLaps + 1) / (1.0 + ((tdble)HCtx[idx]->NbPitStopProg)) + 20.0; GfParmSetNum(*carParmHandle, SECT_CAR, PRM_FUEL, (char*)NULL, fuel); Vtarget = curTrack->pits.speedLimit; if (DrvInfo != NULL) { GfParmReleaseHandle(DrvInfo); } } /* * Function * * * Description * * * Parameters * * * Return * */ void newrace(int index, tCarElt* car, tSituation *s) { int i; int idx = index - 1; for (i = 0; i < MAX_GEARS; i++) { if (car->_gearRatio[i] != 0) { HCtx[idx]->shiftThld[i] = car->_enginerpmRedLine * car->_wheelRadius(2) * 0.85 / car->_gearRatio[i]; GfOut("Gear %d: Spd %f\n", i, HCtx[idx]->shiftThld[i] * 3.6); } else { HCtx[idx]->shiftThld[i] = 10000.0; } } if (HCtx[idx]->MouseControlUsed) { GfctrlMouseCenter(); } memset(keyInfo, 0, sizeof(keyInfo)); memset(skeyInfo, 0, sizeof(skeyInfo)); memset(currentKey, 0, sizeof(currentKey)); memset(currentSKey, 0, sizeof(currentSKey)); #ifndef WIN32 #ifdef TELEMETRY if (s->_raceType == RM_TYPE_PRACTICE) { RtTelemInit(-10, 10); RtTelemNewChannel("Dist", &HCtx[idx]->distToStart, 0, 0); RtTelemNewChannel("Ax", &car->_accel_x, 0, 0); RtTelemNewChannel("Ay", &car->_accel_y, 0, 0); RtTelemNewChannel("Steer", &car->ctrl->steer, 0, 0); RtTelemNewChannel("Throttle", &car->ctrl->accelCmd, 0, 0); RtTelemNewChannel("Brake", &car->ctrl->brakeCmd, 0, 0); RtTelemNewChannel("Gear", &HCtx[idx]->Gear, 0, 0); RtTelemNewChannel("Speed", &car->_speed_x, 0, 0); } #endif #endif } static void updateKeys(void) { int i; int key; int idx; tControlCmd *cmd; for (idx = 0; idx < 10; idx++) { if (HCtx[idx]) { cmd = HCtx[idx]->CmdControl; for (i = 0; i < nbCmdControl; i++) { if (cmd[i].type == GFCTRL_TYPE_KEYBOARD) { key = cmd[i].val; if (currentKey[key] == GFUI_KEY_DOWN) { if (keyInfo[key].state == GFUI_KEY_UP) { keyInfo[key].edgeDn = 1; } else { keyInfo[key].edgeDn = 0; } } else { if (keyInfo[key].state == GFUI_KEY_DOWN) { keyInfo[key].edgeUp = 1; } else { keyInfo[key].edgeUp = 0; } } keyInfo[key].state = currentKey[key]; } if (cmd[i].type == GFCTRL_TYPE_SKEYBOARD) { key = cmd[i].val; if (currentSKey[key] == GFUI_KEY_DOWN) { if (skeyInfo[key].state == GFUI_KEY_UP) { skeyInfo[key].edgeDn = 1; } else { skeyInfo[key].edgeDn = 0; } } else { if (skeyInfo[key].state == GFUI_KEY_DOWN) { skeyInfo[key].edgeUp = 1; } else { skeyInfo[key].edgeUp = 0; } } skeyInfo[key].state = currentSKey[key]; } } } } } static int onKeyAction(unsigned char key, int modifier, int state) { currentKey[key] = state; return 0; } static int onSKeyAction(int key, int modifier, int state) { currentSKey[key] = state; return 0; } static void common_drive(int index, tCarElt* car, tSituation *s) { tdble slip; float ax0; float brake; float clutch; float throttle; float leftSteer; float rightSteer; int scrw, scrh, dummy; int idx = index - 1; tControlCmd *cmd = HCtx[idx]->CmdControl; static int firstTime = 1; if (firstTime) { if (HCtx[idx]->MouseControlUsed) { GfuiMouseShow(); GfctrlMouseInitCenter(); } GfuiKeyEventRegisterCurrent(onKeyAction); GfuiSKeyEventRegisterCurrent(onSKeyAction); firstTime = 0; } HCtx[idx]->distToStart = RtGetDistFromStart(car); HCtx[idx]->Gear = (tdble)car->_gear; /* telemetry */ GfScrGetSize(&scrw, &scrh, &dummy, &dummy); memset(&(car->ctrl), 0, sizeof(tCarCtrl)); car->_lightCmd = HCtx[idx]->lightCmd; if (car->_laps != HCtx[idx]->LastPitStopLap) { car->_raceCmd = RM_CMD_PIT_ASKED; } if (lastKeyUpdate != s->currentTime) { /* Update the controls only once for all the players */ updateKeys(); if (joyPresent) { GfctrlJoyGetCurrent(joyInfo); } GfctrlMouseGetCurrent(mouseInfo); lastKeyUpdate = s->currentTime; } if (((cmd[CMD_ABS].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_ABS].val]) || ((cmd[CMD_ABS].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_ABS].val].edgeUp) || ((cmd[CMD_ABS].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_ABS].val].edgeUp)) { HCtx[idx]->ParamAbs = 1 - HCtx[idx]->ParamAbs; sprintf(sstring, "%s/%s/%d", HM_SECT_PREF, HM_LIST_DRV, index); GfParmSetStr(PrefHdle, sstring, HM_ATT_ABS, Yn[1 - HCtx[idx]->ParamAbs]); GfParmWriteFile(NULL, PrefHdle, "Human"); } if (((cmd[CMD_ASR].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_ASR].val]) || ((cmd[CMD_ASR].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_ASR].val].edgeUp) || ((cmd[CMD_ASR].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_ASR].val].edgeUp)) { HCtx[idx]->ParamAsr = 1 - HCtx[idx]->ParamAsr; sprintf(sstring, "%s/%s/%d", HM_SECT_PREF, HM_LIST_DRV, index); GfParmSetStr(PrefHdle, sstring, HM_ATT_ASR, Yn[1 - HCtx[idx]->ParamAsr]); GfParmWriteFile(NULL, PrefHdle, "Human"); } sprintf(car->_msgCmd[0], "%s %s", (HCtx[idx]->ParamAbs ? "ABS" : ""), (HCtx[idx]->ParamAsr ? "ASR" : "")); memcpy(car->_msgColorCmd, color, sizeof(car->_msgColorCmd)); if (((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_JOY_BUT) && (joyInfo->levelup[cmd[CMD_SPDLIM].val] == 1)) || ((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_KEYBOARD) && (keyInfo[cmd[CMD_SPDLIM].val].state == GFUI_KEY_DOWN)) || ((cmd[CMD_SPDLIM].type == GFCTRL_TYPE_SKEYBOARD) && (skeyInfo[cmd[CMD_SPDLIM].val].state == GFUI_KEY_DOWN))) { speedLimiter = 1; sprintf(car->_msgCmd[1], "Speed Limiter On"); } else { speedLimiter = 0; sprintf(car->_msgCmd[1], "Speed Limiter Off"); } if (((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_LIGHT1].val]) || ((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_LIGHT1].val].edgeUp) || ((cmd[CMD_LIGHT1].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_LIGHT1].val].edgeUp)) { if (HCtx[idx]->lightCmd & RM_LIGHT_HEAD1) { HCtx[idx]->lightCmd &= ~(RM_LIGHT_HEAD1 | RM_LIGHT_HEAD2); } else { HCtx[idx]->lightCmd |= RM_LIGHT_HEAD1 | RM_LIGHT_HEAD2; } } switch (cmd[CMD_LEFTSTEER].type) { case GFCTRL_TYPE_JOY_AXIS: ax0 = joyInfo->ax[cmd[CMD_LEFTSTEER].val]; if (ax0 > cmd[CMD_LEFTSTEER].max) { ax0 = cmd[CMD_LEFTSTEER].max; } else if (ax0 < cmd[CMD_LEFTSTEER].min) { ax0 = cmd[CMD_LEFTSTEER].min; } leftSteer = -SIGN(ax0) * cmd[CMD_LEFTSTEER].pow * pow(fabs(ax0), cmd[CMD_LEFTSTEER].sens) / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->_speed_x); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_LEFTSTEER].val] - cmd[CMD_LEFTSTEER].deadZone; if (ax0 > cmd[CMD_LEFTSTEER].max) { ax0 = cmd[CMD_LEFTSTEER].max; } else if (ax0 < cmd[CMD_LEFTSTEER].min) { ax0 = cmd[CMD_LEFTSTEER].min; } ax0 = ax0 * cmd[CMD_LEFTSTEER].pow; leftSteer = pow(fabs(ax0), cmd[CMD_LEFTSTEER].sens) / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->_speed_x / 10.0); break; case GFCTRL_TYPE_KEYBOARD: case GFCTRL_TYPE_SKEYBOARD: case GFCTRL_TYPE_JOY_BUT: if (cmd[CMD_LEFTSTEER].type == GFCTRL_TYPE_KEYBOARD) { ax0 = keyInfo[cmd[CMD_LEFTSTEER].val].state; } else if (cmd[CMD_LEFTSTEER].type == GFCTRL_TYPE_SKEYBOARD) { ax0 = skeyInfo[cmd[CMD_LEFTSTEER].val].state; } else { ax0 = joyInfo->levelup[cmd[CMD_LEFTSTEER].val]; } if (ax0 == 0) { HCtx[idx]->prevLeftSteer = leftSteer = 0; } else { ax0 = 2 * ax0 - 1; leftSteer = HCtx[idx]->prevLeftSteer + ax0 * cmd[CMD_LEFTSTEER].sens * s->deltaTime / (1.0 + cmd[CMD_LEFTSTEER].spdSens * car->_speed_x / 10.0); if (leftSteer > 1.0) leftSteer = 1.0; if (leftSteer < 0.0) leftSteer = 0.0; HCtx[idx]->prevLeftSteer = leftSteer; } break; default: leftSteer = 0; break; } switch (cmd[CMD_RIGHTSTEER].type) { case GFCTRL_TYPE_JOY_AXIS: ax0 = joyInfo->ax[cmd[CMD_RIGHTSTEER].val]; if (ax0 > cmd[CMD_RIGHTSTEER].max) { ax0 = cmd[CMD_RIGHTSTEER].max; } else if (ax0 < cmd[CMD_RIGHTSTEER].min) { ax0 = cmd[CMD_RIGHTSTEER].min; } rightSteer = -SIGN(ax0) * cmd[CMD_RIGHTSTEER].pow * pow(fabs(ax0), cmd[CMD_RIGHTSTEER].sens) / (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->_speed_x); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_RIGHTSTEER].val] - cmd[CMD_RIGHTSTEER].deadZone; if (ax0 > cmd[CMD_RIGHTSTEER].max) { ax0 = cmd[CMD_RIGHTSTEER].max; } else if (ax0 < cmd[CMD_RIGHTSTEER].min) { ax0 = cmd[CMD_RIGHTSTEER].min; } ax0 = ax0 * cmd[CMD_RIGHTSTEER].pow; rightSteer = - pow(fabs(ax0), cmd[CMD_RIGHTSTEER].sens) / (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->_speed_x / 10.0); break; case GFCTRL_TYPE_KEYBOARD: case GFCTRL_TYPE_SKEYBOARD: case GFCTRL_TYPE_JOY_BUT: if (cmd[CMD_RIGHTSTEER].type == GFCTRL_TYPE_KEYBOARD) { ax0 = keyInfo[cmd[CMD_RIGHTSTEER].val].state; } else if (cmd[CMD_RIGHTSTEER].type == GFCTRL_TYPE_SKEYBOARD) { ax0 = skeyInfo[cmd[CMD_RIGHTSTEER].val].state; } else { ax0 = joyInfo->levelup[cmd[CMD_RIGHTSTEER].val]; } if (ax0 == 0) { HCtx[idx]->prevRightSteer = rightSteer = 0; } else { ax0 = 2 * ax0 - 1; rightSteer = HCtx[idx]->prevRightSteer - ax0 * cmd[CMD_RIGHTSTEER].sens * s->deltaTime/ (1.0 + cmd[CMD_RIGHTSTEER].spdSens * car->_speed_x / 10.0); if (rightSteer > 0.0) rightSteer = 0.0; if (rightSteer < -1.0) rightSteer = -1.0; HCtx[idx]->prevRightSteer = rightSteer; } break; default: rightSteer = 0; break; } car->_steerCmd = leftSteer + rightSteer; switch (cmd[CMD_BRAKE].type) { case GFCTRL_TYPE_JOY_AXIS: brake = joyInfo->ax[cmd[CMD_BRAKE].val]; if (brake > cmd[CMD_BRAKE].max) { brake = cmd[CMD_BRAKE].max; } else if (brake < cmd[CMD_BRAKE].min) { brake = cmd[CMD_BRAKE].min; } car->_brakeCmd = fabs(cmd[CMD_BRAKE].pow * pow(fabs((brake - cmd[CMD_BRAKE].minVal) / (cmd[CMD_BRAKE].max - cmd[CMD_BRAKE].min)), cmd[CMD_BRAKE].sens)); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_BRAKE].val] - cmd[CMD_BRAKE].deadZone; if (ax0 > cmd[CMD_BRAKE].max) { ax0 = cmd[CMD_BRAKE].max; } else if (ax0 < cmd[CMD_BRAKE].min) { ax0 = cmd[CMD_BRAKE].min; } ax0 = ax0 * cmd[CMD_BRAKE].pow; car->_brakeCmd = pow(fabs(ax0), cmd[CMD_BRAKE].sens) / (1.0 + cmd[CMD_BRAKE].spdSens * car->_speed_x / 10.0); break; case GFCTRL_TYPE_JOY_BUT: car->_brakeCmd = joyInfo->levelup[cmd[CMD_BRAKE].val]; break; case GFCTRL_TYPE_MOUSE_BUT: car->_brakeCmd = mouseInfo->button[cmd[CMD_BRAKE].val]; break; case GFCTRL_TYPE_KEYBOARD: car->_brakeCmd = keyInfo[cmd[CMD_BRAKE].val].state; break; case GFCTRL_TYPE_SKEYBOARD: car->_brakeCmd = skeyInfo[cmd[CMD_BRAKE].val].state; break; default: car->_brakeCmd = 0; break; } switch (cmd[CMD_CLUTCH].type) { case GFCTRL_TYPE_JOY_AXIS: clutch = joyInfo->ax[cmd[CMD_CLUTCH].val]; if (clutch > cmd[CMD_CLUTCH].max) { clutch = cmd[CMD_CLUTCH].max; } else if (clutch < cmd[CMD_CLUTCH].min) { clutch = cmd[CMD_CLUTCH].min; } car->_clutchCmd = fabs(cmd[CMD_CLUTCH].pow * pow(fabs((clutch - cmd[CMD_CLUTCH].minVal) / (cmd[CMD_CLUTCH].max - cmd[CMD_CLUTCH].min)), cmd[CMD_CLUTCH].sens)); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_CLUTCH].val] - cmd[CMD_CLUTCH].deadZone; if (ax0 > cmd[CMD_CLUTCH].max) { ax0 = cmd[CMD_CLUTCH].max; } else if (ax0 < cmd[CMD_CLUTCH].min) { ax0 = cmd[CMD_CLUTCH].min; } ax0 = ax0 * cmd[CMD_CLUTCH].pow; car->_clutchCmd = pow(fabs(ax0), cmd[CMD_CLUTCH].sens) / (1.0 + cmd[CMD_CLUTCH].spdSens * car->_speed_x / 10.0); break; case GFCTRL_TYPE_JOY_BUT: car->_clutchCmd = joyInfo->levelup[cmd[CMD_CLUTCH].val]; break; case GFCTRL_TYPE_MOUSE_BUT: car->_clutchCmd = mouseInfo->button[cmd[CMD_CLUTCH].val]; break; case GFCTRL_TYPE_KEYBOARD: car->_clutchCmd = keyInfo[cmd[CMD_CLUTCH].val].state; break; case GFCTRL_TYPE_SKEYBOARD: car->_clutchCmd = skeyInfo[cmd[CMD_CLUTCH].val].state; break; default: car->_clutchCmd = 0; break; } switch (cmd[CMD_THROTTLE].type) { case GFCTRL_TYPE_JOY_AXIS: throttle = joyInfo->ax[cmd[CMD_THROTTLE].val]; if (throttle > cmd[CMD_THROTTLE].max) { throttle = cmd[CMD_THROTTLE].max; } else if (throttle < cmd[CMD_THROTTLE].min) { throttle = cmd[CMD_THROTTLE].min; } car->_accelCmd = fabs(cmd[CMD_THROTTLE].pow * pow(fabs((throttle - cmd[CMD_THROTTLE].minVal) / (cmd[CMD_THROTTLE].max - cmd[CMD_THROTTLE].min)), cmd[CMD_THROTTLE].sens)); break; case GFCTRL_TYPE_MOUSE_AXIS: ax0 = mouseInfo->ax[cmd[CMD_THROTTLE].val] - cmd[CMD_THROTTLE].deadZone; if (ax0 > cmd[CMD_THROTTLE].max) { ax0 = cmd[CMD_THROTTLE].max; } else if (ax0 < cmd[CMD_THROTTLE].min) { ax0 = cmd[CMD_THROTTLE].min; } ax0 = ax0 * cmd[CMD_THROTTLE].pow; car->_accelCmd = pow(fabs(ax0), cmd[CMD_THROTTLE].sens) / (1.0 + cmd[CMD_THROTTLE].spdSens * car->_speed_x / 10.0); if (isnan (car->_accelCmd)) { car->_accelCmd = 0; } /* printf(" axO:%f accelCmd:%f\n", ax0, car->_accelCmd); */ break; case GFCTRL_TYPE_JOY_BUT: car->_accelCmd = joyInfo->levelup[cmd[CMD_THROTTLE].val]; break; case GFCTRL_TYPE_MOUSE_BUT: car->_accelCmd = mouseInfo->button[cmd[CMD_THROTTLE].val]; break; case GFCTRL_TYPE_KEYBOARD: car->_accelCmd = keyInfo[cmd[CMD_THROTTLE].val].state; break; case GFCTRL_TYPE_SKEYBOARD: car->_accelCmd = skeyInfo[cmd[CMD_THROTTLE].val].state; break; default: car->_accelCmd = 0; break; } if (HCtx[idx]->AutoReverseEngaged) { /* swap brake and throttle */ brake = car->_brakeCmd; car->_brakeCmd = car->_accelCmd; car->_accelCmd = brake; } if (HCtx[idx]->ParamAbs) { tdble meanSpd = 0; int i; slip = 0; for (i = 0; i < 4; i++) { meanSpd += car->_wheelSpinVel(i); } meanSpd /= 4.0; if (meanSpd > 1.0) { for (i = 0; i < 4; i++) { if (((meanSpd - car->_wheelSpinVel(i)) / meanSpd) < -0.1) { slip = 1.0; } } } if (slip != 0) { HCtx[idx]->ABS *= 0.9; if (HCtx[idx]->ABS < 0.1) { HCtx[idx]->ABS = 0.1; } } else { if (HCtx[idx]->ABS < 0.1) { HCtx[idx]->ABS = 0.1; } HCtx[idx]->ABS *= 1.1; if (HCtx[idx]->ABS > 1.0) { HCtx[idx]->ABS = 1.0; } } car->_brakeCmd = MIN(car->_brakeCmd, HCtx[idx]->ABS); } if (HCtx[idx]->ParamAsr) { slip = 0; if (car->_speed_x > 0.1) { slip = (car->_wheelRadius(3) * car->_wheelSpinVel(3) - car->_speed_x); } if (slip > 1.0) { HCtx[idx]->AntiSlip *= 0.9; if (HCtx[idx]->AntiSlip < 0.1) { HCtx[idx]->AntiSlip = 0.1; } } else { if (HCtx[idx]->AntiSlip < 0.1) { HCtx[idx]->AntiSlip = 0.1; } HCtx[idx]->AntiSlip *= 1.1; if (HCtx[idx]->AntiSlip > 1.0) { HCtx[idx]->AntiSlip = 1.0; } } car->_accelCmd = MIN(car->_accelCmd, HCtx[idx]->AntiSlip); } if (speedLimiter) { tdble Dv; if (Vtarget != 0) { Dv = Vtarget - car->_speed_x; if (Dv > 0.0) { car->_accelCmd = MIN(car->_accelCmd, fabs(Dv/6.0)); } else { car->_brakeCmd = MAX(car->_brakeCmd, fabs(Dv/5.0)); car->_accelCmd = 0; } } } #ifndef WIN32 #ifdef TELEMETRY if ((car->_laps > 1) && (car->_laps < 5)) { if (HCtx[idx]->lap == 1) { RtTelemStartMonitoring("Player"); } RtTelemUpdate(car->_curLapTime); } if (car->_laps == 5) { if (HCtx[idx]->lap == 4) { RtTelemShutdown(); } } #endif #endif HCtx[idx]->lap = car->_laps; } /* * Function * * * Description * * * Parameters * * * Return * * * Remarks * */ static void drive_mt(int index, tCarElt* car, tSituation *s) { int i; int idx = index - 1; tControlCmd *cmd = HCtx[idx]->CmdControl; common_drive(index, car, s); car->_gearCmd = car->_gear; /* manual shift sequential */ if (((cmd[CMD_UP_SHFT].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_UP_SHFT].val]) || ((cmd[CMD_UP_SHFT].type == GFCTRL_TYPE_MOUSE_BUT) && mouseInfo->edgeup[cmd[CMD_UP_SHFT].val]) || ((cmd[CMD_UP_SHFT].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_UP_SHFT].val].edgeUp) || ((cmd[CMD_UP_SHFT].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_UP_SHFT].val].edgeUp)) { car->_gearCmd++; } if (((cmd[CMD_DN_SHFT].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_DN_SHFT].val]) || ((cmd[CMD_DN_SHFT].type == GFCTRL_TYPE_MOUSE_BUT) && mouseInfo->edgeup[cmd[CMD_DN_SHFT].val]) || ((cmd[CMD_DN_SHFT].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_DN_SHFT].val].edgeUp) || ((cmd[CMD_DN_SHFT].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_DN_SHFT].val].edgeUp)) { if (HCtx[idx]->SeqShftAllowNeutral || (car->_gearCmd > 1)) { car->_gearCmd--; } } /* manual shift direct */ if (HCtx[idx]->RelButNeutral) { for (i = CMD_GEAR_R; i <= CMD_GEAR_6; i++) { if (((cmd[i].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgedn[cmd[i].val]) || ((cmd[i].type == GFCTRL_TYPE_MOUSE_BUT) && mouseInfo->edgedn[cmd[i].val]) || ((cmd[i].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[i].val].edgeDn) || ((cmd[i].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[i].val].edgeDn)) { car->_gearCmd = 0; } } } for (i = CMD_GEAR_R; i <= CMD_GEAR_6; i++) { if (((cmd[i].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[i].val]) || ((cmd[i].type == GFCTRL_TYPE_MOUSE_BUT) && mouseInfo->edgeup[cmd[i].val]) || ((cmd[i].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[i].val].edgeUp) || ((cmd[i].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[i].val].edgeUp)) { car->_gearCmd = i - CMD_GEAR_N; } } } /* * Function * * * Description * * * Parameters * * * Return * * * Remarks * */ static void drive_at(int index, tCarElt* car, tSituation *s) { int gear, i; int idx = index - 1; tControlCmd *cmd = HCtx[idx]->CmdControl; common_drive(index, car, s); /* shift */ gear = car->_gear; if (gear > 0) { /* return to auto-shift */ HCtx[idx]->manual = 0; } gear += car->_gearOffset; car->_gearCmd = car->_gear; if (!HCtx[idx]->AutoReverse) { /* manual shift */ if (((cmd[CMD_UP_SHFT].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_UP_SHFT].val]) || ((cmd[CMD_UP_SHFT].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_UP_SHFT].val].edgeUp) || ((cmd[CMD_UP_SHFT].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_UP_SHFT].val].edgeUp)) { car->_gearCmd++; HCtx[idx]->manual = 1; } if (((cmd[CMD_DN_SHFT].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[CMD_DN_SHFT].val]) || ((cmd[CMD_DN_SHFT].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[CMD_DN_SHFT].val].edgeUp) || ((cmd[CMD_DN_SHFT].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[CMD_DN_SHFT].val].edgeUp)) { car->_gearCmd--; HCtx[idx]->manual = 1; } /* manual shift direct */ if (HCtx[idx]->RelButNeutral) { for (i = CMD_GEAR_R; i < CMD_GEAR_2; i++) { if (((cmd[i].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgedn[cmd[i].val]) || ((cmd[i].type == GFCTRL_TYPE_MOUSE_BUT) && mouseInfo->edgedn[cmd[i].val]) || ((cmd[i].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[i].val].edgeDn) || ((cmd[i].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[i].val].edgeDn)) { car->_gearCmd = 0; /* return to auto-shift */ HCtx[idx]->manual = 0; } } } for (i = CMD_GEAR_R; i < CMD_GEAR_2; i++) { if (((cmd[i].type == GFCTRL_TYPE_JOY_BUT) && joyInfo->edgeup[cmd[i].val]) || ((cmd[i].type == GFCTRL_TYPE_MOUSE_BUT) && mouseInfo->edgeup[cmd[i].val]) || ((cmd[i].type == GFCTRL_TYPE_KEYBOARD) && keyInfo[cmd[i].val].edgeUp) || ((cmd[i].type == GFCTRL_TYPE_SKEYBOARD) && skeyInfo[cmd[i].val].edgeUp)) { car->_gearCmd = i - CMD_GEAR_N; HCtx[idx]->manual = 1; } } } /* auto shift */ if (!HCtx[idx]->manual && !HCtx[idx]->AutoReverseEngaged) { if (car->_speed_x > HCtx[idx]->shiftThld[gear]) { car->_gearCmd++; } else if ((car->_gearCmd > 1) && (car->_speed_x < (HCtx[idx]->shiftThld[gear-1] - 4.0))) { car->_gearCmd--; } if (car->_gearCmd <= 0) { car->_gearCmd++; } } if (HCtx[idx]->AutoReverse) { /* Automatic Reverse Gear Mode */ if (!HCtx[idx]->AutoReverseEngaged) { if ((car->_brakeCmd > car->_accelCmd) && (car->_speed_x < 1.0)) { HCtx[idx]->AutoReverseEngaged = 1; car->_gearCmd = CMD_GEAR_R - CMD_GEAR_N; } } else { /* currently in autoreverse mode */ if ((car->_brakeCmd > car->_accelCmd) && (car->_speed_x > -1.0) && (car->_speed_x < 1.0)) { HCtx[idx]->AutoReverseEngaged = 0; car->_gearCmd = CMD_GEAR_1 - CMD_GEAR_N; } else { car->_gearCmd = CMD_GEAR_R - CMD_GEAR_N; } } } } static int pitcmd(int index, tCarElt* car, tSituation *s) { tdble f1, f2; tdble ns; int idx = index - 1; HCtx[idx]->NbPitStops++; f1 = car->_tank - car->_fuel; if (HCtx[idx]->NbPitStopProg < HCtx[idx]->NbPitStops) { ns = 1.0; } else { ns = 1.0 + (HCtx[idx]->NbPitStopProg - HCtx[idx]->NbPitStops); } f2 = 0.00065 * (curTrack->length * car->_remainingLaps + car->_trkPos.seg->lgfromstart) / ns - car->_fuel; car->_pitFuel = MAX(MIN(f1, f2), 0); HCtx[idx]->LastPitStopLap = car->_laps; car->_pitRepair = (int)car->_dammage; int i; int key; tControlCmd *cmd; if (HCtx[idx]) { cmd = HCtx[idx]->CmdControl; for (i = 0; i < nbCmdControl; i++) { if (cmd[i].type == GFCTRL_TYPE_KEYBOARD || cmd[i].type == GFCTRL_TYPE_SKEYBOARD) { key = cmd[i].val; keyInfo[key].state = GFUI_KEY_UP; keyInfo[key].edgeDn = 0; keyInfo[key].edgeUp = 0; skeyInfo[key].state = GFUI_KEY_UP; skeyInfo[key].edgeDn = 0; skeyInfo[key].edgeUp = 0; currentKey[key] = GFUI_KEY_UP; currentSKey[key] = GFUI_KEY_UP; } } } return ROB_PIT_MENU; /* The player is able to modify the value by menu */ }