AIPerception::AIPerception(ObjectTag tag, float viewRange, Degree fieldOfView, float memorySpan, Object* owner) { time = 0; this->tag = tag; this->fieldOfView = Math::Cos(fieldOfView.valueRadians(), false); this->memorySpan = memorySpan; this->owner = owner; this->viewRangeSq = viewRange * viewRange; }
void Turboprop::updateForces(float dt, int doUpdate) { if (doUpdate) { //tropospheric model valid up to 11.000m (33.000ft) float altitude=nodes[noderef].AbsPosition.y; //float sea_level_temperature=273.15+15.0; //in Kelvin float sea_level_pressure=101325; //in Pa //float airtemperature=sea_level_temperature-altitude*0.0065; //in Kelvin float airpressure=sea_level_pressure*pow(1.0-0.0065*altitude/288.15, 5.24947); //in Pa airdensity=airpressure*0.0000120896;//1.225 at sea level #ifdef USE_OPENAL //sound update SoundScriptManager::getSingleton().modulate(trucknum, mod_id, rpm); #endif //OPENAL } timer+=dt; //evaluate the rotation speed float velacc=0; for (int i=0; i<numblades; i++) velacc+=(nodes[nodep[i]].Velocity-nodes[noderef].Velocity).length(); rpm=(velacc/numblades) * RAD_PER_SEC_TO_RPM / radius; //check for broken prop Vector3 avg=Vector3::ZERO; for (int i=0; i<numblades; i++) avg+=nodes[nodep[i]].RelPosition; avg=avg/numblades; if ((avg-nodes[noderef].RelPosition).length()>0.4) { failed=true; } //evaluate engine power float enginepower=0; //in kilo-Watt float warmupfactor=1.0; if (warmup) { warmupfactor=(timer-warmupstart)/warmuptime; if (warmupfactor>=1.0) warmup=false; } float revpenalty=1.0; if (reverse) revpenalty=0.5; if (!failed && ignition) enginepower=(0.0575+throtle*revpenalty*0.9425)*fullpower*warmupfactor; //the magic formula float enginecouple=0.0; //in N.m if (rpm>10.0) enginecouple=9549.3*enginepower/rpm; else enginecouple=9549.3*enginepower/10.0; indicated_torque=enginecouple; if (torquenode!=-1) { Vector3 along=nodes[noderef].RelPosition-nodes[nodeback].RelPosition; Plane ppl=Plane(along, 0); Vector3 orth=ppl.projectVector(nodes[noderef].RelPosition)-ppl.projectVector(nodes[torquenode].RelPosition); Vector3 cdir=orth.crossProduct(along); cdir.normalise(); nodes[torquenode].Forces+=(enginecouple/torquedist)*cdir; } float tipforce=(enginecouple/radius)/numblades; //okay, now we know the contribution from the engine //pitch if (fixed_pitch>0) pitch=fixed_pitch; else { if (!reverse) { if (throtle<0.01) { //beta range if (pitch>0 && rpm<regspeed*1.4) pitch-=pitchspeed*dt; if (rpm>regspeed*1.4) pitch+=pitchspeed*dt; } else { float dpitch=rpm-regspeed; if (dpitch>pitchspeed) dpitch=pitchspeed; if (dpitch<-pitchspeed) dpitch=-pitchspeed; if (!(dpitch<0 && pitch<0) && !(dpitch>0 && pitch>45)) pitch+=dpitch*dt; } } else { if (rpm<regspeed*1.1) { if (pitch<-4.0) pitch+=pitchspeed*dt; else pitch-=pitchspeed*dt; } if (rpm>regspeed*1.11) { pitch-=pitchspeed*dt; } } } if (!failed) { axis=nodes[noderef].RelPosition-nodes[nodeback].RelPosition; axis.normalise(); } //estimate amount of energy float estrotenergy=0.5*numblades*nodes[nodep[0]].mass*radius*radius*(rpm/RAD_PER_SEC_TO_RPM)*(rpm/RAD_PER_SEC_TO_RPM); //for each blade float totthrust=0; float tottorque=0; for (int i=0; i<numblades; i++) { if (!failed && ignition) { Vector3 totaltipforce=Vector3::ZERO; //span vector, left to right Vector3 spanv=(nodes[nodep[i]].RelPosition-nodes[noderef].RelPosition); spanv.normalise(); //chord vector, front to back Vector3 refchordv=-axis.crossProduct(spanv); //grab this for propulsive forces Vector3 tipf=-refchordv; totaltipforce+=(tipforce-rpm/10.0)*tipf; //add a bit of mechanical friction //for each blade segment (there are 6 elements) for (int j=0; j<5; j++) //outer to inner, the 6th blade element is ignored { //proportion float proport=((float)j+0.5)/6.0; //evaluate wind direction Vector3 wind=-(nodes[nodep[i]].Velocity*(1.0-proport)+nodes[noderef].Velocity*proport); float wspeed=wind.length(); Vector3 liftv=spanv.crossProduct(-wind); liftv.normalise(); //rotate according to pitch Vector3 chordv=Quaternion(Degree(pitch+twistmap[j]-7.0), spanv)*refchordv; //wing normal Vector3 normv=chordv.crossProduct(spanv); //calculate angle of attack Vector3 pwind=Plane(Vector3::ZERO, normv, chordv).projectVector(wind); Vector3 dumb; Degree daoa; chordv.getRotationTo(pwind).ToAngleAxis(daoa, dumb); float aoa=daoa.valueDegrees(); float raoa=daoa.valueRadians(); if (dumb.dotProduct(spanv)>0) {aoa=-aoa; raoa=-raoa;}; //get airfoil data float cz, cx, cm; airfoil->getparams(aoa, 1.0, 0.0, &cz, &cx, &cm); //surface computation float s=radius*bladewidth/6.0; //drag //wforce=(8.0*cx+cx*cx/(3.14159*radius/0.4))*0.5*airdensity*wspeed*s*wind; Vector3 eforce=(4.0*cx+cx*cx/(3.14159*radius/bladewidth))*0.5*airdensity*wspeed*s*wind; //lift float lift=cz*0.5*airdensity*wspeed*wspeed*s; eforce+=lift*liftv; totthrust+=eforce.dotProduct(axis); //apply forces nodes[noderef].Forces+=eforce*proport; totaltipforce+=eforce*(1.0-proport); // if (i==0) sprintf(debug, "rend %.4i%%, wind %.3i kts, aoa %.3i, power %.5ihp, thrust %.6ilbf, torque %.6ilbft, pitch %.3i, propwash %.3i kts", (int)(100.0*wforce.dotProduct(axis)*numblades*nodes[noderef].Velocity.length()/(rpm*0.10471976*2.0*3.14159*enginecouple)), (int)(wspeed*1.9438), (int)aoa, (int)(enginepower*1.34), (int)(wforce.dotProduct(axis)*numblades*0.2248), (int)(enginecouple/1.35582), (int)pitch, (int)(propwash*1.9438)); // if (i==0) sprintf(debug, "lfx=%f lfy=%f lfz=%f vx=%f vy=%f vz=%f cx=%f cz=%f lift=%f", liftv.x, liftv.y, liftv.z, wind.x, wind.y, wind.z, cx, cz, lift); } tottorque+=tipf.dotProduct(totaltipforce)*radius; //correct amount of energy float correctfactor=0; if (rpm>100) correctfactor=(rotenergy-estrotenergy)/(numblades*radius*dt*rpm/RAD_PER_SEC_TO_RPM); if (correctfactor>1000.0) correctfactor=1000.0; if (correctfactor<-1000.0) correctfactor=-1000.0; nodes[nodep[i]].Forces+=totaltipforce+correctfactor*tipf; } else { //failed case //add drag Vector3 wind=-nodes[nodep[i]].Velocity; // determine nodes speed and divide by engines speed (with some magic numbers for tuning) to keep it rotating longer when shutoff in flight and stop after a while when plane is stopped (on the ground) float wspeed= (wind.length()/15.0f) / (nodes[noderef].Velocity.length()/2.0f); nodes[nodep[i]].Forces+=airdensity*wspeed*wind; } } //compute the next energy level rotenergy+=(double)tottorque*dt*rpm/RAD_PER_SEC_TO_RPM; // sprintf(debug, "pitch %i thrust %i totenergy=%i apparentenergy=%i", (int)pitch, (int)totthrust, (int)rotenergy, (int)estrotenergy); //prop wash float speed=nodes[noderef].Velocity.length(); float thrsign=1.0; if (totthrust<0) {thrsign=-0.1; totthrust=-totthrust;}; if (!failed) propwash=thrsign*sqrt(totthrust/(0.5*airdensity*proparea)+speed*speed)-speed; else propwash=0; if (propwash<0) propwash=0; }
void FlexAirfoil::updateForces() { if(!airfoil) return; if (broken) return; // if (innan) {LOG("STEP "+TOSTRING(innan)+" "+TOSTRING(nblu));innan++;} //evaluate wind direction Vector3 wind=-(nodes[nfld].Velocity+nodes[nfrd].Velocity)/2.0; //add wash int i; for (i=0; i<free_wash; i++) wind-=(0.5*washpropratio[i]*aeroengines[washpropnum[i]]->getpropwash())*aeroengines[washpropnum[i]]->getAxis(); float wspeed=wind.length(); //chord vector, front to back Vector3 chordv=((nodes[nbld].RelPosition-nodes[nfld].RelPosition)+(nodes[nbrd].RelPosition-nodes[nfrd].RelPosition))/2.0; float chord=chordv.length(); //span vector, left to right Vector3 spanv=((nodes[nfrd].RelPosition-nodes[nfld].RelPosition)+(nodes[nbrd].RelPosition-nodes[nbld].RelPosition))/2.0; float span=spanv.length(); //lift vector //if (_isnan(spanv.x) || _isnan(spanv.y) || _isnan(spanv.z)) LOG("spanv is NaN "+TOSTRING(nblu)); //if (_isnan(wind.x) || _isnan(wind.y) || _isnan(wind.z)) LOG("wind is NaN "+TOSTRING(nblu)); Vector3 liftv=spanv.crossProduct(-wind); //if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv0 is NaN "+TOSTRING(nblu)); //if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv1 is NaN "+TOSTRING(nblu)); //wing normal float s=span*chord; Vector3 normv=chordv.crossProduct(spanv); normv.normalise(); //calculate angle of attack Vector3 pwind; pwind=Plane(Vector3::ZERO, normv, chordv).projectVector(-wind); Vector3 dumb; Degree daoa; chordv.getRotationTo(-pwind).ToAngleAxis(daoa, dumb); aoa=daoa.valueDegrees(); float raoa=daoa.valueRadians(); if (dumb.dotProduct(spanv)>0) {aoa=-aoa; raoa=-raoa;}; //if (_isnan(aoa)) LOG("aoa is NaN "+TOSTRING(nblu)); //get airfoil data float cz, cx, cm; if (isstabilator) airfoil->getparams(aoa-deflection, chordratio, 0, &cz, &cx, &cm); else airfoil->getparams(aoa, chordratio, deflection, &cz, &cx, &cm); //compute surface //if (_isnan(cz)) LOG("cz is NaN "+TOSTRING(nblu)); //float fs=span*(fabs(thickness*cos(raoa))+fabs(chord*sin(raoa))); //float ts=span*(fabs(chord*cos(raoa))+fabs(thickness*sin(raoa))); //tropospheric model valid up to 11.000m (33.000ft) float altitude=nodes[nfld].AbsPosition.y; //float sea_level_temperature=273.15+15.0; //in Kelvin (not used) float sea_level_pressure=101325; //in Pa //float airtemperature=sea_level_temperature-altitude*0.0065; //in Kelvin (not used) float airpressure=sea_level_pressure*approx_pow(1.0-0.0065*altitude/288.15, 5.24947); //in Pa float airdensity=airpressure*0.0000120896;//1.225 at sea level Vector3 wforce=Vector3::ZERO; //drag wforce=(cx*0.5*airdensity*wspeed*s)*wind; //if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) LOG("wforce1 is NaN "+TOSTRING(nblu)); //induced drag if (useInducedDrag) { Vector3 idf=(cx*cx*0.25*airdensity*wspeed*idArea*idArea/(3.14159*idSpan*idSpan))*wind; //if (_isnan(idf.length())) LOG("idf is NaN "+TOSTRING(nblu)); if (idLeft) { nodes[nblu].Forces+=idf; nodes[nbld].Forces+=idf; } else { nodes[nbru].Forces+=idf; nodes[nbrd].Forces+=idf; } } //if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) LOG("wforce1a is NaN "+TOSTRING(nblu)); //if (_isnan(cz)) LOG("cz is NaN "+TOSTRING(nblu)); //if (_isnan(wspeed)) LOG("wspeed is NaN "+TOSTRING(nblu)); //if (_isnan(airdensity)) LOG("airdensity is NaN "+TOSTRING(nblu)); //if (_isnan(s)) LOG("s is NaN "+TOSTRING(nblu)); //if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv is NaN "+TOSTRING(nblu)); //lift wforce+=(cz*0.5*airdensity*wspeed*chord)*liftv; /*if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) { if (innan==0) innan=1; LOG("wforce2 is NaN "+TOSTRING(nblu)); } */ //moment float moment=-cm*0.5*airdensity*wspeed*wspeed*s;//*chord; //apply forces Vector3 f1=wforce*(liftcoef * 0.75/4.0f)+normv*(liftcoef *moment/(4.0f*0.25f)); Vector3 f2=wforce*(liftcoef *0.25/4.0f)-normv*(liftcoef *moment/(4.0f*0.75f)); //focal at 0.25 chord nodes[nfld].Forces+=f1; nodes[nflu].Forces+=f1; nodes[nfrd].Forces+=f1; nodes[nfru].Forces+=f1; nodes[nbld].Forces+=f2; nodes[nblu].Forces+=f2; nodes[nbrd].Forces+=f2; nodes[nbru].Forces+=f2; // sprintf(debug, "wind %i kts, aoa %i, cz %f, vf %f ", (int)(wspeed*1.9438), (int)aoa, cz, normv.y); }
inline Radian::Radian(Degree degrees) : mRadValue(degrees.valueRadians()) {}
void LandVehicleSimulation::UpdateVehicle(Beam* curr_truck, float seconds_since_last_frame) { using namespace Ogre; if (!curr_truck->replaymode) { if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_LEFT_MIRROR_LEFT)) curr_truck->leftMirrorAngle-=0.001; if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_LEFT_MIRROR_RIGHT)) curr_truck->leftMirrorAngle+=0.001; if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_RIGHT_MIRROR_LEFT)) curr_truck->rightMirrorAngle-=0.001; if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_RIGHT_MIRROR_RIGHT)) curr_truck->rightMirrorAngle+=0.001; } // end of (!curr_truck->replaymode) block #ifdef USE_ANGELSCRIPT if (!curr_truck->replaymode && !curr_truck->vehicle_ai->IsActive()) #else if (!curr_truck->replaymode) #endif // USE_ANGELSCRIPT { // steering float tmp_left_digital = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_LEFT, false, InputEngine::ET_DIGITAL); float tmp_right_digital = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_RIGHT, false, InputEngine::ET_DIGITAL); float tmp_left_analog = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_LEFT, false, InputEngine::ET_ANALOG); float tmp_right_analog = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_RIGHT, false, InputEngine::ET_ANALOG); float sum = -std::max(tmp_left_digital,tmp_left_analog)+ std::max(tmp_right_digital,tmp_right_analog); if (sum < -1) sum = -1; if (sum > 1) sum = 1; curr_truck->hydrodircommand = sum; if ((tmp_left_digital < tmp_left_analog) || (tmp_right_digital < tmp_right_analog)) { curr_truck->hydroSpeedCoupling = false; } else { curr_truck->hydroSpeedCoupling = true; } if (curr_truck->engine) { static bool arcadeControls = BSETTING("ArcadeControls", false); float accl = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE); float brake = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE); if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_25) || RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_50)) { float acclModifier = 0.0f; if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_25)) { acclModifier += 0.25f; } if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_50)) { acclModifier += 0.50f; } accl *= acclModifier; } if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_25) || RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_50)) { float brakeModifier = 0.0f; if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_25)) { brakeModifier += 0.25f; } if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_50)) { brakeModifier += 0.50f; } brake *= brakeModifier; } // arcade controls are only working with auto-clutch! if (!arcadeControls || curr_truck->engine->getAutoMode() > BeamEngine::SEMIAUTO) { // classic mode, realistic curr_truck->engine->autoSetAcc(accl); curr_truck->brake = brake * curr_truck->brakeforce; } else { // start engine if (curr_truck->engine->hasContact() && !curr_truck->engine->isRunning() && (accl > 0 || brake > 0)) { curr_truck->engine->start(); } // arcade controls: hey - people wanted it x| ... <- and it's convenient if (curr_truck->engine->getGear() >= 0) { // neutral or drive forward, everything is as its used to be: brake is brake and accel. is accel. curr_truck->engine->autoSetAcc(accl); curr_truck->brake = brake * curr_truck->brakeforce; } else { // reverse gear, reverse controls: brake is accel. and accel. is brake. curr_truck->engine->autoSetAcc(brake); curr_truck->brake = accl * curr_truck->brakeforce; } // only when the truck really is not moving anymore if (fabs(curr_truck->WheelSpeed) <= 1.0f) { Vector3 hdir = curr_truck->getDirection(); float velocity = hdir.dotProduct(curr_truck->nodes[0].Velocity); // switching point, does the user want to drive forward from backward or the other way round? change gears? if (velocity < 1.0f && brake > 0.5f && accl < 0.5f && curr_truck->engine->getGear() > 0) { // we are on the brake, jump to reverse gear if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC) { curr_truck->engine->autoShiftSet(BeamEngine::REAR); } else { curr_truck->engine->setGear(-1); } } else if (velocity > -1.0f && brake < 0.5f && accl > 0.5f && curr_truck->engine->getGear() < 0) { // we are on the gas pedal, jump to first gear when we were in rear gear if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC) { curr_truck->engine->autoShiftSet(BeamEngine::DRIVE); } else { curr_truck->engine->setGear(1); } } } } // IMI // gear management -- it might, should be transferred to a standalone function of Beam or RoRFrameListener if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC) { if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_AUTOSHIFT_UP)) { curr_truck->engine->autoShiftUp(); } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_AUTOSHIFT_DOWN)) { curr_truck->engine->autoShiftDown(); } } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TOGGLE_CONTACT)) { curr_truck->engine->toggleContact(); } if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_STARTER) && curr_truck->engine->hasContact() && !curr_truck->engine->isRunning()) { // starter curr_truck->engine->setstarter(1); #ifdef USE_OPENAL SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_STARTER); #endif // OPENAL } else { curr_truck->engine->setstarter(0); #ifdef USE_OPENAL SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_STARTER); #endif // OPENAL } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SWITCH_SHIFT_MODES)) { // toggle Auto shift curr_truck->engine->toggleAutoMode(); // force gui update curr_truck->triggerGUIFeaturesChanged(); #ifdef USE_MYGUI switch(curr_truck->engine->getAutoMode()) { case BeamEngine::AUTOMATIC: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Automatic shift"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Automatic shift"); break; case BeamEngine::SEMIAUTO: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Manual shift - Auto clutch"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Manual shift - Auto clutch"); break; case BeamEngine::MANUAL: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully Manual: sequential shift"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully Manual: sequential shift"); break; case BeamEngine::MANUAL_STICK: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully manual: stick shift"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully manual: stick shift"); break; case BeamEngine::MANUAL_RANGES: RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully Manual: stick shift with ranges"), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully Manual: stick shift with ranges"); break; } #endif //USE_MYGUI } // joy clutch float cval = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_MANUAL_CLUTCH); curr_truck->engine->setManualClutch(cval); int shiftmode = curr_truck->engine->getAutoMode(); if (shiftmode <= BeamEngine::MANUAL) // auto, semi auto and sequential shifting { if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_UP)) { curr_truck->engine->shift(1); } else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_DOWN)) { if (shiftmode > BeamEngine::SEMIAUTO || shiftmode == BeamEngine::SEMIAUTO && !arcadeControls || shiftmode == BeamEngine::SEMIAUTO && curr_truck->engine->getGear() > 0 || shiftmode == BeamEngine::AUTOMATIC) { curr_truck->engine->shift(-1); } } else if (shiftmode != BeamEngine::AUTOMATIC && RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_NEUTRAL)) { curr_truck->engine->shiftTo(0); } } else //if (shiftmode > BeamEngine::MANUAL) // h-shift or h-shift with ranges shifting { bool gear_changed = false; bool found = false; int curgear = curr_truck->engine->getGear(); int curgearrange = curr_truck->engine->getGearRange(); int gearoffset = std::max(0, curgear - curgearrange * 6); // one can select range only if in neutral if (shiftmode==BeamEngine::MANUAL_RANGES && curgear == 0) { // maybe this should not be here, but should experiment if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_LOWRANGE) && curgearrange != 0) { curr_truck->engine->setGearRange(0); gear_changed = true; #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Low range selected"), "cog.png", 3000); #endif //USE_MYGUI } else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_MIDRANGE) && curgearrange != 1 && curr_truck->engine->getNumGearsRanges()>1) { curr_truck->engine->setGearRange(1); gear_changed = true; #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Mid range selected"), "cog.png", 3000); #endif //USE_MYGUI } else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_HIGHRANGE) && curgearrange != 2 && curr_truck->engine->getNumGearsRanges()>2) { curr_truck->engine->setGearRange(2); gear_changed = true; #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("High range selected"), "cog.png", 3000); #endif // USE_MYGUI } } //zaxxon if (curgear == -1) { gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR_REVERSE); } else if (curgear > 0 && curgear < 19) { if (shiftmode==BeamEngine::MANUAL) { gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + curgear -1); } else { gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + gearoffset-1); // range mode } } if (gear_changed || curgear == 0) { if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR_REVERSE)) { curr_truck->engine->shiftTo(-1); found = true; } else if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_NEUTRAL)) { curr_truck->engine->shiftTo(0); found = true; } else { if (shiftmode == BeamEngine::MANUAL_STICK) { for (int i=1; i < 19 && !found; i++) { if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + i - 1)) { curr_truck->engine->shiftTo(i); found = true; } } } else // BeamEngine::MANUALMANUAL_RANGES { for (int i=1; i < 7 && !found; i++) { if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + i - 1)) { curr_truck->engine->shiftTo(i + curgearrange * 6); found = true; } } } } if (!found) { curr_truck->engine->shiftTo(0); } } // end of if (gear_changed) } // end of shitmode > BeamEngine::MANUAL if (curr_truck->engine->hasContact() && curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC && curr_truck->engine->getAutoShift() != BeamEngine::NEUTRAL && std::abs(curr_truck->WheelSpeed) < 0.1f) { Vector3 dirDiff = curr_truck->getDirection(); Degree pitchAngle = Radian(asin(dirDiff.dotProduct(Vector3::UNIT_Y))); if (std::abs(pitchAngle.valueDegrees()) > 1.0f) { if (curr_truck->engine->getAutoShift() > BeamEngine::NEUTRAL && curr_truck->WheelSpeed < +0.1f && pitchAngle.valueDegrees() > +1.0f || curr_truck->engine->getAutoShift() < BeamEngine::NEUTRAL && curr_truck->WheelSpeed > -0.1f && pitchAngle.valueDegrees() < -1.0f) { // anti roll back in BeamEngine::AUTOMATIC (DRIVE, TWO, ONE) mode // anti roll forth in BeamEngine::AUTOMATIC (REAR) mode float downhill_force = std::abs(sin(pitchAngle.valueRadians()) * curr_truck->getTotalMass()); float engine_force = std::abs(curr_truck->engine->getTorque()); float ratio = std::max(0.0f, 1.0f - (engine_force / downhill_force) / 2.0f); curr_truck->brake = curr_truck->brakeforce * sqrt(ratio); } } else if (brake == 0.0f && accl == 0.0f && curr_truck->parkingbrake == 0) { float ratio = std::max(0.0f, 0.1f - std::abs(curr_truck->WheelSpeed)) * 5.0f; curr_truck->brake = curr_truck->brakeforce * ratio; } } } // end of ->engine #ifdef USE_OPENAL if (curr_truck->brake > curr_truck->brakeforce / 6.0f) { SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_BRAKE); } else { SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_BRAKE); } #endif // USE_OPENAL } // end of ->replaymode if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TOGGLE_AXLE_LOCK)) { // toggle auto shift if (!curr_truck->getAxleLockCount()) { #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("No differential installed on current vehicle!"), "warning.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Differential:", "No differential installed on current vehicle!"); #endif // USE_MYGUI } else { curr_truck->toggleAxleLock(); #ifdef USE_MYGUI RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Differentials switched to: ") + curr_truck->getAxleLockName(), "cog.png", 3000); RoR::Application::GetGuiManager()->PushNotification("Differential:", "Differentials switched to: " + curr_truck->getAxleLockName()); #endif // USE_MYGUI } } #ifdef USE_OPENAL if (curr_truck->ispolice) { if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_HORN)) { SoundScriptManager::getSingleton().trigToggle(curr_truck, SS_TRIG_HORN); } } else { if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_HORN) && !curr_truck->replaymode) { SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_HORN); } else { SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_HORN); } } #endif // OPENAL if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_PARKING_BRAKE)) { curr_truck->parkingbrakeToggle(); } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_ANTILOCK_BRAKE)) { if (curr_truck->alb_present && !curr_truck->alb_notoggle) { curr_truck->antilockbrakeToggle(); } } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TRACTION_CONTROL)) { if (!curr_truck->tc_notoggle) curr_truck->tractioncontrolToggle(); } if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_CRUISE_CONTROL)) { curr_truck->cruisecontrolToggle(); } if (curr_truck->cc_mode) { LandVehicleSimulation::UpdateCruiseControl(curr_truck, seconds_since_last_frame); } LandVehicleSimulation::CheckSpeedLimit(curr_truck, seconds_since_last_frame); }
Radian::Radian(const Degree& d) : mRad(d.valueRadians()) {}
Radian Radian::operator-(const Degree& d) const { return Radian(mRad - d.valueRadians()); }
//--------------------------------------------------------------------- void LiSPSMShadowCameraSetup::setCameraLightDirectionThreshold(Degree angle) { mCosCamLightDirThreshold = Math::Cos(angle.valueRadians()); }