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;
}
Exemple #2
0
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;
}
Exemple #3
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);

}
Exemple #4
0
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);
}
Exemple #6
0
	Radian::Radian(const Degree& d) : mRad(d.valueRadians()) {}
Exemple #7
0
	Radian Radian::operator-(const Degree& d) const {
		return Radian(mRad - d.valueRadians());
	}
	//---------------------------------------------------------------------
	void LiSPSMShadowCameraSetup::setCameraLightDirectionThreshold(Degree angle)
	{
		mCosCamLightDirThreshold = Math::Cos(angle.valueRadians());
	}