/* ----------------------------------------------------------------------------- This source file is part of OpenSpace3D For the latest info, see http://www.openspace3d.com Copyright (c) 2012 I-maginer This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt ----------------------------------------------------------------------------- */ struct ObjTireStr = [ PTIRE_wheelObject : SO3_OBJECT, PTIRE_partSmoke : SO3_OBJECT, PTIRE_fSpringDamping : F, PTIRE_fSpringLength : F, PTIRE_bDriving : I, PTIRE_bDirectional : I, PTIRE_fMass : F, PTIRE_fRadius : F, PTIRE_fWidth : F, PTIRE_fFriction : F, PTIRE_fLastDiff : F, PTIRE_sndScreech : ObjAudio, PTIRE_restoreWheel : [[F F F] [F F F F]] ]mkObjTireStr;; struct ObjCameraPhys = [ PCAM_camera : SO3_OBJECT, PCAM_shell : SO3_OBJECT, PCAM_initQuat : [F F F F], PCAM_from : [F F F F], PCAM_dest : [F F F F], PCAM_fCoef : F, PCAM_fminDist : F, PCAM_fmaxDist : F, PCAM_fAngle : F ]mkObjCameraPhysStr;; struct ObjVehicleStr = [ PVEHICLE_inst : PInstance, PVEHICLE_child : SO3_OBJECT, PVEHICLE_body : SO3_PHYSICBODY, PVEHICLE_bRemoveBody : I, PVEHICLE_joint : SO3_PHYSICCONTRAINT, PVEHICLE_physiqueMat : SO3_PHYSICMATERIAL, PVEHICLE_tireMat : SO3_PHYSICMATERIAL, PVEHICLE_fMass : F, PVEHICLE_fEnginePower : F, PVEHICLE_iNbGears : I, PVEHICLE_bAutoGear : I, PVEHICLE_fFriction : F, PVEHICLE_matBrake : [SO3_MATERIAL I I], PVEHICLE_bDriftpart : I, PVEHICLE_sndEngineStart : ObjAudio, PVEHICLE_sndEngineLoop : ObjAudio, PVEHICLE_sndShock : ObjAudio, PVEHICLE_camera : ObjCameraPhys, PVEHICLE_lTires : [ObjTireStr r1], PVEHICLE_iNbDirTires : I, PVEHICLE_iNbDriveTires : I, PVEHICLE_iNbTires : I, PVEHICLE_fWheelRadius : F, PVEHICLE_iCurGear : I, PVEHICLE_fCurAccel : F, PVEHICLE_fCurTurn : F, PVEHICLE_iLastGear : I, PVEHICLE_fLastAccel : F, PVEHICLE_bBrake : I, PVEHICLE_bStarted : I, PVEHICLE_bTireOverlap : I, PVEHICLE_fLastTireAng : F, PVEHICLE_lControls : [[S [[F F F] [F F F] F I I]] r1], PVEHICLE_move : [[F F F] [F F F]], PVEHICLE_restoreVehicle : [F [F F F] [F F F F] [I I I I]], // car mass, car position PVEHICLE_iCurrentRpm : I, PVEHICLE_bReverse : I ]mkObjVehicleStr;; var lGearRatios = [-1 2.90]::[0 1.0]::[1 2.66]::[2 1.78]::[3 1.3]::[4 1.0]::[5 0.74]::[6 0.5]::nil;; fun computeControls(obstr, ftime, fspeed)= let ftime /. 1000.0 -> nbsec in let if nbsec == 0.0 then 0.0001 else nbsec -> nbsec in let [nbsec nbsec nbsec] -> vnbsec in let [ftime ftime ftime] -> vtime in let [fspeed fspeed fspeed] -> vspeed in // analogic data let [0.0 0.0 0.0] -> avec in let [0.0 0.0 0.0] -> aang in // real data let [0.0 0.0 0.0] -> vec in let [0.0 0.0 0.0] -> ang in let 0.0 -> ycam in let 0 -> angOverride in ( let sizelist obstr.PVEHICLE_lControls -> size in let 0 -> i in while i < size do ( let nth_list obstr.PVEHICLE_lControls i -> [_ tcontrol] in let tcontrol -> [nvec nang nycam mode newdata] in if (!newdata) then nil else ( if (mode == 1) then // accumulator ( set vec = addVectorF vec nvec; if (angOverride) then nil else set ang = addVectorF ang nang; set ycam = ycam +. nycam; //reset control mutate tcontrol <- [[0.0 0.0 0.0] [0.0 0.0 0.0] 0.0 mode 0]; 0; ) else if (mode == 2) then // override angle ( set angOverride = 1; set vec = addVectorF vec nvec; set ang = nang; set ycam = ycam +. nycam; //reset control mutate tcontrol <- [[0.0 0.0 0.0] [0.0 0.0 0.0] 0.0 mode 0]; 0; ) else ( set avec = addVectorF avec nvec; set aang = addVectorF aang nang; mutate tcontrol <- [_ _ _ _ 0]; 0; ) ); set i = i + 1; ); // compute speed and time set avec = multiplyVectorF multiplyVectorF avec vnbsec [2.0 2.0 2.0]; //2 meter per second ? //set aang = multiplyVectorF multiplyVectorF aang vnbsec [90.0 90.0 90.0]; //90 degree per second ? set avec = multiplyVectorF avec vspeed; let aang -> [pitch yaw roll] in set aang = [(SO3MathsDegreeToRadian pitch) (SO3MathsDegreeToRadian yaw) (SO3MathsDegreeToRadian roll)]; let ang -> [ax ay az] in set ang = [(SO3MathsDegreeToRadian ax) (SO3MathsDegreeToRadian ay) (SO3MathsDegreeToRadian az)]; let if (angOverride) then ang else (addVectorF aang ang) -> fang in [(addVectorF avec vec) fang ycam angOverride]; );; fun deleteOb(inst, obstr)= SO3PhysicsContraintDestroy obstr.PVEHICLE_joint; //reset objects bodies and positions let obstr.PVEHICLE_restoreVehicle -> [omass pos quat [ambcolor diffcolor speccolor illcolor]] in ( if (obstr.PVEHICLE_bRemoveBody) then ( SO3BodyDestroy obstr.PVEHICLE_body; 0; ) else ( SO3BodySetMass obstr.PVEHICLE_body omass; 0; ); SO3ObjectSetPosition obstr.PVEHICLE_child pos; SO3ObjectSetOrientation obstr.PVEHICLE_child quat; //restore material let obstr.PVEHICLE_matBrake -> [mat itech ipass] in ( SO3MaterialSetAmbientByTechAndPass mat itech ipass ambcolor; SO3MaterialSetDiffuseByTechAndPass mat itech ipass diffcolor; SO3MaterialSetSpecularByTechAndPass mat itech ipass speccolor; SO3MaterialSetSelfIlluminationByTechAndPass mat itech ipass illcolor; ); ); while (obstr.PVEHICLE_lTires != nil) do ( let hd obstr.PVEHICLE_lTires -> tirestr in let tirestr.PTIRE_restoreWheel -> [wpos wquat] in ( SO3ObjectSetPosition tirestr.PTIRE_wheelObject wpos; SO3ObjectSetOrientation tirestr.PTIRE_wheelObject wquat; _DSAudio tirestr.PTIRE_sndScreech; SO3ObjectDestroy tirestr.PTIRE_partSmoke; ); set obstr.PVEHICLE_lTires = tl obstr.PVEHICLE_lTires; ); SO3PhysicsMaterialDestroy obstr.PVEHICLE_physiqueMat; SO3PhysicsMaterialDestroy obstr.PVEHICLE_tireMat; setPluginInstanceCbScenePreRenderPhysic inst nil; setPluginInstanceCbScenePreRender2 inst nil; //stop sounds _DSAudio obstr.PVEHICLE_sndEngineStart; _DSAudio obstr.PVEHICLE_sndEngineLoop; _DSAudio obstr.PVEHICLE_sndShock; //destroy camera V3DdelCamera c3dXsession obstr.PVEHICLE_camera.PCAM_camera; SO3ObjectDestroy obstr.PVEHICLE_camera.PCAM_shell; set obstr.PVEHICLE_lControls = nil; SO3GroupDelete (V3DgetSession c3dXsession) strcat (getPluginInstanceName inst) "_Group"; 0;; fun cbAccelerate(inst, from, action, param, reply, obstr)= let if (atof param) == nil then 0.0 else if (atof param) <. 0.0 then 0.0 else if (atof param) >. 1.0 then 1.0 else (atof param) -> accel in if (obstr.PVEHICLE_bReverse && (accel == 0.0)) then nil else ( if (!obstr.PVEHICLE_bAutoGear || (obstr.PVEHICLE_iCurGear != -1)) then nil else ( set obstr.PVEHICLE_iCurGear = 1; SendPluginEvent inst "Gear" itoa obstr.PVEHICLE_iCurGear nil; ); set obstr.PVEHICLE_fCurAccel = accel; set obstr.PVEHICLE_bReverse = 0; ); 0;; fun cbTurn(inst, from, action, param, reply, obstr)= let if (atof param) == nil then 0.0 else if (atof param) <. (-.1.0) then (-.1.0) else if (atof param) >. 1.0 then 1.0 else (atof param) -> turn in set obstr.PVEHICLE_fCurTurn = turn; 0;; fun cbStartBrake(inst, from, action, param, reply, obstr)= let if (atof param) == nil then 0.5 else (atof param) *. 0.5 -> brake in SO3PhysicsContraintSetVehicleBrake obstr.PVEHICLE_joint brake; //brake material let obstr.PVEHICLE_matBrake -> [mat itech ipass] in let make_rgba 255 0 0 128 -> brakeColor in ( SO3MaterialSetAmbientByTechAndPass mat itech ipass brakeColor; SO3MaterialSetDiffuseByTechAndPass mat itech ipass brakeColor; //SO3MaterialSetSpecularByTechAndPass mat itech ipass speccolor; SO3MaterialSetSelfIlluminationByTechAndPass mat itech ipass brakeColor; ); set obstr.PVEHICLE_bBrake = 1; 0;; fun cbHandBrake(inst, from, action, param, reply, obstr)= SO3PhysicsContraintSetVehicleBrake obstr.PVEHICLE_joint 0.5; //brake material let obstr.PVEHICLE_matBrake -> [mat itech ipass] in let make_rgba 255 0 0 128 -> brakeColor in ( SO3MaterialSetAmbientByTechAndPass mat itech ipass brakeColor; SO3MaterialSetDiffuseByTechAndPass mat itech ipass brakeColor; //SO3MaterialSetSpecularByTechAndPass mat itech ipass speccolor; SO3MaterialSetSelfIlluminationByTechAndPass mat itech ipass brakeColor; ); set obstr.PVEHICLE_bBrake = 1; 0;; fun cbStopBrake(inst, from, action, param, reply, obstr)= SO3PhysicsContraintSetVehicleBrake obstr.PVEHICLE_joint 0.0; //restore brake material let obstr.PVEHICLE_restoreVehicle -> [omass pos quat [ambcolor diffcolor speccolor illcolor]] in let obstr.PVEHICLE_matBrake -> [mat itech ipass] in ( SO3MaterialSetAmbientByTechAndPass mat itech ipass ambcolor; SO3MaterialSetDiffuseByTechAndPass mat itech ipass diffcolor; SO3MaterialSetSpecularByTechAndPass mat itech ipass speccolor; SO3MaterialSetSelfIlluminationByTechAndPass mat itech ipass illcolor; ); set obstr.PVEHICLE_bBrake = 0; 0;; fun cbRear(inst, from, action, param, reply, obstr)= let if (atof param) == nil then 0.0 else if (atof param) <. 0.0 then 0.0 else if (atof param) >. 1.0 then 1.0 else (atof param) -> accel in ( if ((accel == 0.0) && !obstr.PVEHICLE_bReverse) then nil else ( set obstr.PVEHICLE_bReverse = if (accel == 0.0) then 0 else 1; if (obstr.PVEHICLE_bReverse && (obstr.PVEHICLE_iCurrentRpm != 0)) then ( cbStartBrake inst nil nil param nil obstr; 0; ) else ( if (!obstr.PVEHICLE_bBrake) then nil else cbStopBrake inst nil nil param nil obstr; 0; ); if (obstr.PVEHICLE_iCurGear == -1) then nil else ( set obstr.PVEHICLE_iCurGear = -1; SendPluginEvent inst "Gear" itoa obstr.PVEHICLE_iCurGear nil; ); set obstr.PVEHICLE_fCurAccel = accel; ); ); 0;; fun cbGearUp(inst, from, action, param, reply, obstr)= let if obstr.PVEHICLE_iCurGear == obstr.PVEHICLE_iNbGears then obstr.PVEHICLE_iNbGears else obstr.PVEHICLE_iCurGear + 1 -> gear in set obstr.PVEHICLE_iCurGear = gear; SendPluginEvent inst "Gear" itoa obstr.PVEHICLE_iCurGear nil; 0;; fun cbGearDown(inst, from, action, param, reply, obstr)= let if obstr.PVEHICLE_iCurGear <= (-1) then -1 else obstr.PVEHICLE_iCurGear - 1 -> gear in set obstr.PVEHICLE_iCurGear = gear; SendPluginEvent inst "Gear" itoa obstr.PVEHICLE_iCurGear nil; 0;; fun rotateCamera(obstr, ftime)= let obstr.PVEHICLE_camera -> camstr in let 1.0 -> rspeed in let ftime /. 1000.0 -> nbsec in let (camstr.PCAM_fCoef +. (rspeed *. nbsec)) -> coef in let if (coef >. 1.0) then 1.0 else if (coef <. 0.0) then 0.0 else coef -> coef in if ((coef -. camstr.PCAM_fCoef) == 0.0) && (camstr.PCAM_fCoef != 0.0) then ( SO3ObjectSetOrientation camstr.PCAM_shell camstr.PCAM_dest; ) else ( let SO3MathsQuatInterpolate camstr.PCAM_from camstr.PCAM_dest coef 1 -> tang in SO3ObjectSetOrientation camstr.PCAM_shell tang; set camstr.PCAM_fCoef = coef; 0; ); 0;; fun cbPreRenderCamera(inst, sessionstr, etime, obstr)= //update camera let if (etime == 0) then 1.0 else (itof etime) /. 1000.0 -> ftime in let obstr.PVEHICLE_camera -> camstr in let SO3ObjectGetGlobalOrientation obstr.PVEHICLE_child -> cargquat in let SO3MathsQuatGetYaw cargquat 1 -> cy in let if (obstr.PVEHICLE_iCurGear < 0) then SO3MathsEulerYXZToQuat [(SO3MathsDegreeToRadian camstr.PCAM_fAngle) 0.0 0.0] else SO3MathsEulerYXZToQuat [(SO3MathsDegreeToRadian camstr.PCAM_fAngle) (SO3MathsDegreeToRadian 180.0) 0.0] -> basequat in let SO3MathsQuatAdd (SO3MathsEulerYXZToQuat [0.0 cy 0.0]) basequat -> [qx qy qz qw] in let camstr.PCAM_dest -> [dx dy dz dw] in //if ((qx == dx) && (qy == dy) && (qz == dz) && (qw == dw)) then nil else let SO3BodyGetVelocity obstr.PVEHICLE_body -> [vx vy vz] in let sqrt ((vx *. vx) +. (vy *. vy) +. (vz *. vz)) -> mspeed in let mspeed *. 3.6 -> kspeed in ( set camstr.PCAM_from = SO3ObjectGetOrientation camstr.PCAM_shell; set camstr.PCAM_dest = [qx qy qz qw]; set camstr.PCAM_fCoef = 0.0; let camstr.PCAM_fminDist +. ((camstr.PCAM_fmaxDist -. camstr.PCAM_fminDist) *. ((maxf kspeed 1.0) /. 100.0)) -> camdist in let if camdist >. camstr.PCAM_fmaxDist then camstr.PCAM_fmaxDist else camdist -> camdist in SO3ObjectSetPosition camstr.PCAM_camera [0.0 0.0 camdist]; SO3ObjectSetPosition camstr.PCAM_shell SO3ObjectGetGlobalPosition obstr.PVEHICLE_child; rotateCamera obstr ftime; ); 0;; fun cbContraintPreRender(inst, sessionstr, etime, obstr)= set obstr.PVEHICLE_bTireOverlap = !SO3PhysicsContraintGetVehicleOnAir obstr.PVEHICLE_joint; let obstr.PVEHICLE_camera -> camstr in let SO3ObjectGetGlobalOrientation obstr.PVEHICLE_child -> cargquat in let SO3BodyGetVelocity obstr.PVEHICLE_body -> [vx vy vz] in let sqrt ((vx *. vx) +. (vy *. vy) +. (vz *. vz)) -> mspeed in //let absf SO3PhysicsContraintGetVehicleSpeed obstr.PVEHICLE_joint -> mspeed in let if (obstr.PVEHICLE_iCurGear == 0) then 1000.0 else 1000.0 +. 1000.0 *. (itof obstr.PVEHICLE_iNbGears) *. (obstr.PVEHICLE_fEnginePower /. 1000.0) -> maxRpm in let switch lGearRatios obstr.PVEHICLE_iCurGear -> gearRatio in let if (abs obstr.PVEHICLE_iCurGear < 1) then 1.0 else switch lGearRatios obstr.PVEHICLE_iCurGear - 1 -> prevGearRatio in let 3.42 -> differential in let obstr.PVEHICLE_fEnginePower -> epower in let V3DphysGetGravity c3dXsession -> [_ ygrav _] in let if (obstr.PVEHICLE_fWheelRadius == 0.0) then 0.0 else mspeed *. obstr.PVEHICLE_fWheelRadius -> curRate in let (curRate *. gearRatio *. differential) *. 60.0 /. 2.0 *. PIf -> curRpm in let if curRpm >. maxRpm then maxRpm else curRpm -> curRpm in let let 0.0 -> avom in ( let obstr.PVEHICLE_lTires -> ltire in let 0 -> i in while (ltire != nil) do ( let hd ltire -> tirestr in ( let (absf SO3PhysicsContraintGetVehicleTireAngularVelocity obstr.PVEHICLE_joint tirestr.PTIRE_wheelObject) /. (absf ygrav) -> homega in let SO3PhysicsContraintGetVehicleTireOnAir obstr.PVEHICLE_joint tirestr.PTIRE_wheelObject -> onair in ( if (!tirestr.PTIRE_bDriving) then nil else set avom = if avom == 0.0 then homega else minf avom homega; // update screech sound let (curRate -. homega) -> diff in let absf (tirestr.PTIRE_fLastDiff -. diff) *. 10.0 -> screech in let SO3ObjectGetGlobalPosition tirestr.PTIRE_wheelObject -> pos in let SO3ObjectGetGlobalOrientation tirestr.PTIRE_wheelObject -> tquat in ( let SO3MathsQuatGetDirection tquat [1.0 1.0 1.0] -> dir in _AudioSetPosition tirestr.PTIRE_sndScreech pos dir; set tirestr.PTIRE_fLastDiff = diff; if (!onair && screech >. 0.001 && screech <. 10.0) then ( let 1.0 +. screech /. 10.0 -> sscreech in let if sscreech >. 1.2 then 1.2 else sscreech -> sscreech in _AudioSetPitch tirestr.PTIRE_sndScreech sscreech; let (ftoi (screech *. 80.0)) -> vol in let if vol > 100 then 100 else vol -> vol in _AudioSetVolume tirestr.PTIRE_sndScreech vol; if ((screech <. 0.15) || (!obstr.PVEHICLE_bDriftpart)) then nil else ( let pos -> [px py pz] in let [px ((py-.tirestr.PTIRE_fRadius) +. 0.01) pz] -> epos in let SO3MathsQuatToEulerYXZ cargquat -> [ax ay az] in ( SO3ObjectSetGlobalPosition tirestr.PTIRE_partSmoke epos; SO3ParticleSystemSetEnable tirestr.PTIRE_partSmoke 1; ); ); 0; ) else ( _AudioSetVolume tirestr.PTIRE_sndScreech 0; 0; ); ); ); ); set ltire = tl ltire; ); avom; ) -> curWheelRate in let (curWheelRate *. gearRatio *. differential) *. 60.0 /. 2.0 *. PIf -> curWheelRpm in let if curWheelRpm == 0.0 then curRpm else if curWheelRpm >. maxRpm then maxRpm else curWheelRpm -> curWheelRpm in let if curRpm == 0.0 || !obstr.PVEHICLE_bTireOverlap then curWheelRpm else minf curRpm curWheelRpm -> curWheelRpm in let mspeed *. 3.6 -> kspeed in let if (etime == 0) then 1.0 else (itof etime) /. 1000.0 -> ftime in ( let computeControls obstr ftime 1.0 -> [[tleft forward tright] [pitch yaw roll] ycam angOverride] in let 90.0 *. (ftime /. 1000.0) -> angspeed in let (-.(obstr.PVEHICLE_fCurTurn) +. (SO3MathsRadianToDegree yaw)) *. 30.0 -> maxctrl in let (-.(obstr.PVEHICLE_fCurTurn) +. (SO3MathsRadianToDegree yaw)) *. angspeed -> angctrl in let if angctrl == 0.0 && obstr.PVEHICLE_fLastTireAng != 0.0 then if obstr.PVEHICLE_fLastTireAng >. 0.0 then -.angspeed else angspeed else angctrl -> angstep in let obstr.PVEHICLE_fLastTireAng +. angstep -> ang in let if (obstr.PVEHICLE_fLastTireAng <. 0.0 && angctrl == 0.0 && ang >. 0.0) || (obstr.PVEHICLE_fLastTireAng >. 0.0 && angctrl == 0.0 && ang <. 0.0) then 0.0 else ang -> ang in let if ang >. maxctrl && maxctrl >. 0.0 then maxctrl else if ang <. maxctrl && maxctrl <. 0.0 then maxctrl else ang -> ang in ( SO3PhysicsContraintSetVehicleSteerAngle obstr.PVEHICLE_joint SO3MathsDegreeToRadian ang; SendPluginEvent inst "Steer angle" ftoa (-.ang) nil; set obstr.PVEHICLE_fLastTireAng = ang; ); if (!obstr.PVEHICLE_bStarted) then nil else ( let (curRpm /. maxRpm) -> fx in // ((- (x*x) + (2 - 1/5)) * (x*x) + (1/5)) let if (obstr.PVEHICLE_iCurGear == 0) then 1.0 else (itof (abs obstr.PVEHICLE_iCurGear)) -> fgear in let epower *. ((-.(fx *. fx) +. (2.0 -. (1.0 /. fgear))) *. (fx *. fx) +. (1.0 /. fgear)) -> engineTorque in //let ((2.0 *. PIf *. engineTorque *. differential) /. (60.0 *. gearRatio)) -> womega in let engineTorque *. gearRatio *. differential *. obstr.PVEHICLE_fCurAccel -> wheelTorque in ( // auto gear if (obstr.PVEHICLE_bAutoGear && (obstr.PVEHICLE_iCurGear == obstr.PVEHICLE_iLastGear) && obstr.PVEHICLE_iCurGear >= 0) then ( if ((engineTorque <=. (epower -. (epower *. 0.4))) && (obstr.PVEHICLE_iCurGear > 1)) then ( //gear down set obstr.PVEHICLE_iCurGear = obstr.PVEHICLE_iCurGear - 1; SendPluginEvent inst "Gear" itoa obstr.PVEHICLE_iCurGear nil; ) else if (((engineTorque >=. (epower -. (epower *. 0.05))) || (obstr.PVEHICLE_iCurGear == 0)) && (obstr.PVEHICLE_iCurGear < obstr.PVEHICLE_iNbGears) && obstr.PVEHICLE_bTireOverlap && (obstr.PVEHICLE_fCurAccel >. 0.0)) then ( //gear up set obstr.PVEHICLE_iCurGear = obstr.PVEHICLE_iCurGear + 1; SendPluginEvent inst "Gear" itoa obstr.PVEHICLE_iCurGear nil; ) else nil; ) else nil; // update gear if (/*(obstr.PVEHICLE_fLastAccel == obstr.PVEHICLE_fCurAccel && obstr.PVEHICLE_iCurGear == obstr.PVEHICLE_iLastGear) ||*/ obstr.PVEHICLE_bBrake) then nil else ( set obstr.PVEHICLE_iLastGear = obstr.PVEHICLE_iCurGear; set obstr.PVEHICLE_fLastAccel = obstr.PVEHICLE_fCurAccel; if (obstr.PVEHICLE_iCurGear == 0) || (obstr.PVEHICLE_fCurAccel == 0.0) then ( SO3PhysicsContraintSetVehicleDrivingTorque obstr.PVEHICLE_joint 0.0; 0; ) else ( SO3PhysicsContraintSetVehicleDrivingTorque obstr.PVEHICLE_joint if (obstr.PVEHICLE_iCurGear < 0) then -.wheelTorque else wheelTorque; 0; ); ); // update sounds position let SO3ObjectGetGlobalPosition obstr.PVEHICLE_child -> pos in let SO3MathsQuatGetDirection cargquat [1.0 1.0 1.0] -> dir in ( _AudioSetPosition obstr.PVEHICLE_sndEngineStart pos dir; _AudioSetPosition obstr.PVEHICLE_sndEngineLoop pos dir; _AudioSetPosition obstr.PVEHICLE_sndShock pos dir; //_AudioSetVolume obstr.PVEHICLE_sndEngineLoop 100; let (curWheelRpm *. 0.0001) -> pitch in ( _AudioSetPitch obstr.PVEHICLE_sndEngineLoop (0.5 +. pitch); _AudioSetVolume obstr.PVEHICLE_sndEngineLoop 30 + (ftoi (pitch *. 150.0)); ); ); set obstr.PVEHICLE_iCurrentRpm = (ftoi curWheelRpm); SendPluginEvent inst "Speed" itoa (ftoi kspeed) nil; SendPluginEvent inst "Rpm" itoa (ftoi curWheelRpm) nil; if (!obstr.PVEHICLE_bReverse || (obstr.PVEHICLE_iCurrentRpm != 0)) then nil else ( if (!obstr.PVEHICLE_bBrake) then nil else cbStopBrake inst nil nil nil nil obstr; set obstr.PVEHICLE_iCurGear = -1; SendPluginEvent inst "Gear" itoa obstr.PVEHICLE_iCurGear nil; ); ); ); ); 0;; fun computeMass(obstr)= if (obstr.PVEHICLE_iNbTires == 0) then nil else ( let obstr.PVEHICLE_fMass -> mass in let itof obstr.PVEHICLE_iNbTires -> nbtire in let mass /. nbtire *. 0.05 -> tiremass in let mass -. (tiremass *. nbtire) -> vehiclemass in ( SO3BodySetMass obstr.PVEHICLE_body vehiclemass; //SO3BodySetContiniousCollisionMode obstr.PVEHICLE_body 1; let sizelist obstr.PVEHICLE_lTires -> size in let 0 -> i in while (i < size) do ( let nth_list obstr.PVEHICLE_lTires i -> tirestr in ( set tirestr.PTIRE_fMass = tiremass; ); set i = i +1; ); ); ); 0;; fun loadWheels(obstr)= //add a group ressource for particles if (!obstr.PVEHICLE_bDriftpart) then nil else let strcat (getPluginInstanceName obstr.PVEHICLE_inst) "_Group" -> groupname in ( SO3GroupCreate (V3DgetSession c3dXsession) groupname; V3DaddResource c3dXsession strcatn (getPluginDirectory (getInstancePlugin obstr.PVEHICLE_inst))::"/part/smoke_particle.png"::nil groupname SO3_RESOURCE_TEXTURE; V3DaddResource c3dXsession strcatn (getPluginDirectory (getInstancePlugin obstr.PVEHICLE_inst))::"/part/smoke.material"::nil groupname SO3_RESOURCE_MATERIAL; V3DaddResource c3dXsession strcatn (getPluginDirectory (getInstancePlugin obstr.PVEHICLE_inst))::"/part/smoke.particle"::nil groupname SO3_RESOURCE_PARTICLE_SYSTEM; ); let 0 -> i in ( let (getPluginInstanceParam obstr.PVEHICLE_inst "sndscreech") -> sndscreech in let getPluginInstanceParam obstr.PVEHICLE_inst (strcat "wheel_" (itoa i)) -> wheel in let atof getPluginInstanceParam obstr.PVEHICLE_inst (strcat "dampinglength_" (itoa i)) -> dampinglength in let atof getPluginInstanceParam obstr.PVEHICLE_inst (strcat "damping_" (itoa i)) -> damping in let atoi getPluginInstanceParam obstr.PVEHICLE_inst (strcat "driving_" (itoa i)) -> driving in let atoi getPluginInstanceParam obstr.PVEHICLE_inst (strcat "directional_" (itoa i)) -> directional in while (wheel != nil) do ( let SO3SceneGetObject (V3DgetSession c3dXsession) wheel -> wheelobj in let [(SO3ObjectGetPosition wheelobj) (SO3ObjectGetOrientation wheelobj)] -> restorewheel in let (SO3ObjectGetGlobalPosition wheelobj) -> gpos in let gpos -> [gx gy gz] in let SO3ObjectGetBoundingBoxInfo wheelobj 0 -> [[x y z] _ _] in let [(if x <=. 0.0 then 0.01 else x) (if y <=. 0.0 then 0.01 else y) (if z <=. 0.0 then 0.01 else z)] -> [x y z] in let if x >=. y && x >=. z then [(x /. 2.0) (if y >. z then z else y)] else if y >=. x && y >=. z then [(y /. 2.0) (if x >. z then z else x)] else [(z /. 2.0) (if x >. y then y else x)] -> [wradius wwidth] in let mkObjTireStr [wheelobj nil damping dampinglength driving directional 0.0 wradius wwidth obstr.PVEHICLE_fFriction 0.0 nil restorewheel] -> tirestr in ( set obstr.PVEHICLE_fWheelRadius = obstr.PVEHICLE_fWheelRadius +. wradius; set tirestr.PTIRE_sndScreech = _CRAudio _channel (strcatn (getPluginInstanceName obstr.PVEHICLE_inst)::".steer_"::(itoa i)::nil) (_checkpack sndscreech) 0; _AudioSetVolume tirestr.PTIRE_sndScreech 0; _AudioPlay3d tirestr.PTIRE_sndScreech 10.0 1; _AudioEnableSoundEffect tirestr.PTIRE_sndScreech 1; //particle if (!obstr.PVEHICLE_bDriftpart) then nil else ( set tirestr.PTIRE_partSmoke = V3DaddParticleSystem c3dXsession (strcatn (getPluginInstanceName obstr.PVEHICLE_inst)::".steer_part_"::(itoa i)::nil) "tire_smoke"; SO3ObjectSetScale tirestr.PTIRE_partSmoke [(0.3 *. wradius) (0.3 *. wradius) (0.3 *. wradius)]; SO3ParticleSystemSetEnable tirestr.PTIRE_partSmoke 0; ); set obstr.PVEHICLE_iNbTires = obstr.PVEHICLE_iNbTires + 1; set obstr.PVEHICLE_lTires = tirestr::obstr.PVEHICLE_lTires; set obstr.PVEHICLE_iNbDirTires = obstr.PVEHICLE_iNbDirTires + tirestr.PTIRE_bDirectional; set obstr.PVEHICLE_iNbDriveTires = obstr.PVEHICLE_iNbDriveTires + tirestr.PTIRE_bDriving; //SO3ObjectSetGlobalPosition wheelobj [gx (gy -. (tirestr.PTIRE_fSpringLength /. 2.0)) gz]; ); set i = i + 1; set wheel = getPluginInstanceParam obstr.PVEHICLE_inst (strcat "wheel_" (itoa i)); set dampinglength = atof getPluginInstanceParam obstr.PVEHICLE_inst (strcat "dampinglength_" (itoa i)); set damping = atof getPluginInstanceParam obstr.PVEHICLE_inst (strcat "damping_" (itoa i)); set driving = atoi getPluginInstanceParam obstr.PVEHICLE_inst (strcat "driving_" (itoa i)); set directional = atoi getPluginInstanceParam obstr.PVEHICLE_inst (strcat "directional_" (itoa i)); ); if (obstr.PVEHICLE_iNbTires == 0) then nil else set obstr.PVEHICLE_fWheelRadius = obstr.PVEHICLE_fWheelRadius /. (itof obstr.PVEHICLE_iNbTires); 0; );; fun cbReset(inst, from, action, param, reply, obstr)= if (obstr.PVEHICLE_iCurGear == 0) then nil else ( set obstr.PVEHICLE_iCurGear = 0; SendPluginEvent inst "Gear" itoa obstr.PVEHICLE_iCurGear nil; ); set obstr.PVEHICLE_fCurAccel = 0.0; let SO3MathsQuatGetYaw (SO3ObjectGetGlobalOrientation obstr.PVEHICLE_child) 1 -> yaw in let SO3ObjectGetGlobalPosition obstr.PVEHICLE_child -> [x y z] in ( SO3BodySetOmega obstr.PVEHICLE_body [0.0 0.0 0.0]; SO3BodySetVelocity obstr.PVEHICLE_body [0.0 0.0 0.0]; SO3ObjectSetGlobalPosition obstr.PVEHICLE_child [x (y +. 2.0) z]; SO3ObjectSetGlobalOrientation obstr.PVEHICLE_child (SO3MathsEulerYXZToQuat [0.0 yaw 0.0]); ); 0;; fun cbSoundStartEnd(snd, obstr)= //_AudioPlay3d obstr.PVEHICLE_sndEngineLoop 1.0 1; 0;; fun cbStart(inst, from, action, param, reply, obstr)= set obstr.PVEHICLE_bStarted = 1; _AudioPlay3d obstr.PVEHICLE_sndEngineStart 10.0 0; _AudioSetVolume obstr.PVEHICLE_sndEngineLoop 0; _AudioPlay3d obstr.PVEHICLE_sndEngineLoop 10.0 1; 0;; fun cbStop(inst, from, action, param, reply, obstr)= set obstr.PVEHICLE_bStarted = 0; _AudioStop obstr.PVEHICLE_sndEngineLoop; 0;; fun cbCarContact(scene, obstr, body1, body2, pos, normal, force, normalspeed)= if _AudioIsPlaying obstr.PVEHICLE_sndShock then nil else ( _AudioSetVolume obstr.PVEHICLE_sndShock (ftoi (absf normalspeed *. 100.0)); _AudioPlay3d obstr.PVEHICLE_sndShock 10.0 0; ); 0;; fun cbEnableCamera(inst, from, action, param, reply, obstr)= V3DsetDefaultCamera c3dXsession obstr.PVEHICLE_camera.PCAM_camera; 0;; fun cbDisableCamera(inst, from, action, param, reply, obstr)= V3DremoveDefaultCamera c3dXsession obstr.PVEHICLE_camera.PCAM_camera; 0;; fun cbAutoTrans(inst, from, action, param, reply, obstr)= let if (atoi param) == nil then 0 else (atoi param) -> state in set obstr.PVEHICLE_bAutoGear = state; 0;; fun loadCamera(inst, obstr)= let atof (getPluginInstanceParam inst "nclip") -> nclip in let atof (getPluginInstanceParam inst "fclip") -> fclip in let atof (getPluginInstanceParam inst "fovy") -> fovy in let atof (getPluginInstanceParam inst "mindist") -> mindist in let atof (getPluginInstanceParam inst "maxdist") -> maxdist in let atof (getPluginInstanceParam inst "camangle") -> camangle in let atoi (getPluginInstanceParam inst "enablecam") -> enablecam in let V3DaddCamera c3dXsession strcat (getPluginInstanceName inst) "_camera" -> cam in let SO3MathsEulerYXZToQuat [(SO3MathsDegreeToRadian camangle) (SO3MathsDegreeToRadian 180.0) 0.0] -> initquat in let V3DaddShell c3dXsession strcat (getPluginInstanceName inst) "_cam_dummy" nil nil [0.0 0.0 0.0] initquat -> shell in let mkObjCameraPhysStr [cam shell initquat initquat initquat 0.0 mindist maxdist camangle] -> camstr in ( set obstr.PVEHICLE_camera = camstr; SO3ObjectLink cam shell; SO3ObjectSetPosition cam [0.0 0.0 maxdist]; V3DsetCamera cam 1.0 (SO3MathsDegreeToRadian fovy) nclip fclip; if (!enablecam) then nil else cbEnableCamera inst nil nil nil nil obstr; ); 0;; fun cbControl(inst, from, action, param, reply, obstr)= if (!obstr.PVEHICLE_bStarted) then nil else //get the input control from the link let if reply == nil then "control" else reply -> reply in let switchstr obstr.PVEHICLE_lControls reply -> icontrol in ( // if not already int the list we add it if (icontrol != nil) then nil else ( set obstr.PVEHICLE_lControls = [reply [[0.0 0.0 0.0] [0.0 0.0 0.0] 0.0 0 1]]::obstr.PVEHICLE_lControls; set icontrol = switchstr obstr.PVEHICLE_lControls reply; //addLogMessage strcat "add control " reply; ); let strextr param -> l in let hd l -> sv in let hd tl l -> sa in let hd (hd tl tl l) -> mode in let icontrol -> [ovec oang ycam _ _] in let ovec -> [ovx ovy ovz] in let oang -> [oax oay oaz] in let if mode == nil then 0 else atoi mode -> imode in let [(nth_list sv 0) (nth_list sv 1) (nth_list sv 2)] -> [svx svy svz] in let [(if (!strcmp "_" svx) || (svx == nil) then ovx else (atof svx)) (if (!strcmp "_" svy) || (svy == nil) then ovy else (atof svy)) (if (!strcmp "_" svz) || (svz == nil) then ovz else (atof svz))] -> [vx vy vz] in let [(nth_list sa 0) (nth_list sa 1) (nth_list sa 2)] -> [sax say saz] in let [(if (!strcmp "_" sax) || (sax == nil) then oax else (atof sax)) (if (!strcmp "_" say) || (say == nil) then oay else (atof say)) (if (!strcmp "_" saz) || (saz == nil) then oaz else (atof saz))] -> [ax ay az] in ( if (imode == 1) then // accumulator mutate icontrol <- [(addVectorF ovec [vx 0.0 vz]) (addVectorF oang [ax ay az]) (ycam +. vy) imode 1] else if (imode == 2) then // override orientation mutate icontrol <- [(addVectorF ovec [vx 0.0 vz]) [ax ay az] (ycam +. vy) imode 1] else mutate icontrol <- [[vx vy vz] [ax ay az] 0.0 imode 1]; ); ); 0;; fun cbInitPlugs(inst, obstr)= cbStart obstr.PVEHICLE_inst nil nil nil nil obstr; 0;; fun initCar(obstr)= // wheels loadWheels obstr; SO3BodySetAutoSleep obstr.PVEHICLE_body 0; computeMass obstr; set obstr.PVEHICLE_joint = SO3PhysicsContraintCreateVehicle (V3DgetSession c3dXsession) obstr.PVEHICLE_body; // add wheels to the car joint let sizelist obstr.PVEHICLE_lTires -> size in let 0 -> i in while (i < size) do ( let nth_list obstr.PVEHICLE_lTires i -> tirestr in ( SO3PhysicsContraintAddVehicleTire obstr.PVEHICLE_joint tirestr.PTIRE_wheelObject tirestr.PTIRE_fMass tirestr.PTIRE_fRadius tirestr.PTIRE_fWidth tirestr.PTIRE_fFriction tirestr.PTIRE_fSpringLength 250.0 tirestr.PTIRE_fSpringDamping tirestr.PTIRE_bDirectional tirestr.PTIRE_bDriving; ); set i = i +1; ); 0;; fun newOb(inst)= let (getPluginInstanceParam inst "object") -> objname in let atof (getPluginInstanceParam inst "mass") -> mass in let atof (getPluginInstanceParam inst "enginepower") -> enginepower in let atoi (getPluginInstanceParam inst "nbgears") -> nbgears in let atoi (getPluginInstanceParam inst "autogear") -> autogear in let atof (getPluginInstanceParam inst "wfriction") -> wfriction in let (getPluginInstanceParam inst "sndstart") -> sndstart in let (getPluginInstanceParam inst "sndloop") -> sndloop in let (getPluginInstanceParam inst "sndshock") -> sndshock in let (getPluginInstanceParam inst "objectmat") -> objmatname in let (getPluginInstanceParam inst "material") -> matname in let atoi (getPluginInstanceParam inst "technique") -> itec in let if itec == nil then 0 else itec -> itec in let atoi (getPluginInstanceParam inst "pass") -> ipass in let if ipass == nil then 0 else ipass -> ipass in let atoi (getPluginInstanceParam inst "driftpart") -> driftpart in let atoi (getPluginInstanceParam inst "startengine") -> startengine in let SO3SceneGetObject (V3DgetSession c3dXsession) objname -> vehicleobj in let SO3SceneNodeGetBody vehicleobj -> vehiclebody in let if vehiclebody == nil then 1 else 0 -> removebody in // create the physic body if not already set let if vehiclebody == nil then 1 else 0 -> bnewbody in let if vehiclebody == nil then SO3BodyCreateShape vehicleobj 0.0 else vehiclebody -> vehiclebody in let SO3SceneGetMaterial (V3DgetSession c3dXsession) (SO3EntityGetResourceGroup vehicleobj) matname -> brakemat in let SO3MaterialGetAmbientByTechAndPass brakemat itec ipass -> defamb in let SO3MaterialGetDiffuseByTechAndPass brakemat itec ipass -> defdiff in let SO3MaterialGetSpecularByTechAndPass brakemat itec ipass -> defspec in let SO3MaterialGetSelfIlluminationByTechAndPass brakemat itec ipass -> defself in let let SO3BodyGetMassMatrix vehiclebody -> [omass _] in [omass (SO3ObjectGetPosition vehicleobj) (SO3ObjectGetOrientation vehicleobj) [defamb defdiff defspec defself]] -> restore in let SO3PhysicsMaterialCreate (V3DgetSession c3dXsession) (strcat (getPluginInstanceName inst) ".mat") -> pmat in let SO3PhysicsMaterialCreate (V3DgetSession c3dXsession) (strcat (getPluginInstanceName inst) ".wmat") -> wmat in let mkObjVehicleStr [inst vehicleobj vehiclebody removebody nil pmat wmat mass enginepower nbgears autogear wfriction [brakemat itec ipass] driftpart nil nil nil nil nil 0 0 0 0.0 0 0.0 0.0 0 0.0 0 startengine 0 0.0 nil [[0.0 0.0 0.0] [0.0 0.0 0.0]] restore 0 0] -> obstr in ( if !bnewbody then nil else let SO3ObjectGetBoundingBoxInfo vehicleobj 0 -> [[x y z] [cx cy cz] _] in ( SO3BodySetCenterOfMass vehiclebody [cx (cy -. y /. 6.0) (cz +. z /. 8.0)]; SO3BodySetContiniousCollisionMode vehiclebody 1; ); // physic mat to disable car collision between bodies SO3PhysicsMaterialSetDefaultCollidable obstr.PVEHICLE_physiqueMat obstr.PVEHICLE_physiqueMat 0; SO3PhysicsMaterialSetDefaultCollidable obstr.PVEHICLE_tireMat obstr.PVEHICLE_physiqueMat 0; SO3BodySetMaterial obstr.PVEHICLE_body obstr.PVEHICLE_physiqueMat; let SO3PhysicsGetMaterial (V3DgetSession c3dXsession) "default" -> defmat in ( // needed for player if (defmat != nil) then nil else set defmat = SO3PhysicsMaterialCreate (V3DgetSession c3dXsession) "default"; SO3PhysicsMaterialSetContiniousCollisionMode obstr.PVEHICLE_tireMat defmat 1; SO3PhysicsMaterialSetDefaultElasticity obstr.PVEHICLE_tireMat defmat 0.002; SO3PhysicsMaterialSetDefaultFriction obstr.PVEHICLE_tireMat defmat 0.9 1.3; SO3PhysicsMaterialSetDefaultSoftness obstr.PVEHICLE_tireMat defmat 0.001; SO3PhysicsMaterialSetSurfaceThickness obstr.PVEHICLE_tireMat defmat 0.001; SO3PhysicsMaterialSetContiniousCollisionMode obstr.PVEHICLE_physiqueMat defmat 1; SO3PhysicsMaterialSetDefaultElasticity obstr.PVEHICLE_physiqueMat defmat 0.01; SO3PhysicsMaterialSetDefaultFriction obstr.PVEHICLE_physiqueMat defmat 0.5 0.5; SO3PhysicsMaterialSetDefaultSoftness obstr.PVEHICLE_physiqueMat defmat 0.01; SO3PhysicsMaterialSetSurfaceThickness obstr.PVEHICLE_physiqueMat defmat 0.01; SO3CbMaterialCollision obstr.PVEHICLE_physiqueMat defmat @cbCarContact obstr; ); initCar obstr; //camera loadCamera inst obstr; // sounds set obstr.PVEHICLE_sndEngineStart = _CRAudio _channel (strcat (getPluginInstanceName inst) ".start") (_checkpack sndstart) 0; set obstr.PVEHICLE_sndEngineLoop = _CRAudio _channel (strcat (getPluginInstanceName inst) ".engine") (_checkpack sndloop) 0; set obstr.PVEHICLE_sndShock= _CRAudio _channel (strcat (getPluginInstanceName inst) ".shock") (_checkpack sndshock) 0; _AudioEnableSoundEffect obstr.PVEHICLE_sndEngineStart 1; _AudioEnableSoundEffect obstr.PVEHICLE_sndEngineLoop 1; _AudioEnableSoundEffect obstr.PVEHICLE_sndShock 1; _CBAudioEnd obstr.PVEHICLE_sndEngineStart @cbSoundStartEnd obstr; PluginRegisterAction inst "Control" mkfun6 @cbControl obstr; PluginRegisterAction inst "Start engine" mkfun6 @cbStart obstr; PluginRegisterAction inst "Stop engine" mkfun6 @cbStop obstr; PluginRegisterAction inst "Accelerate" mkfun6 @cbAccelerate obstr; PluginRegisterAction inst "Reverse" mkfun6 @cbRear obstr; PluginRegisterAction inst "Brake" mkfun6 @cbStartBrake obstr; PluginRegisterAction inst "Stop brake" mkfun6 @cbStopBrake obstr; PluginRegisterAction inst "Hand brake" mkfun6 @cbHandBrake obstr; PluginRegisterAction inst "Turn" mkfun6 @cbTurn obstr; PluginRegisterAction inst "Gear up" mkfun6 @cbGearUp obstr; PluginRegisterAction inst "Gear down" mkfun6 @cbGearDown obstr; PluginRegisterAction inst "Reset" mkfun6 @cbReset obstr; PluginRegisterAction inst "Enable camera" mkfun6 @cbEnableCamera obstr; PluginRegisterAction inst "Disable camera" mkfun6 @cbDisableCamera obstr; PluginRegisterAction inst "Set automatic gearbox" mkfun6 @cbAutoTrans obstr; setPluginInstanceCbScenePreRenderPhysic inst mkfun4 @cbContraintPreRender obstr; setPluginInstanceCbScenePreRender2 inst mkfun4 @cbPreRenderCamera obstr; setPluginInstanceCbDel inst mkfun2 @deleteOb obstr; if (!obstr.PVEHICLE_bStarted) then nil else ( if (inst.INST_groupstr.GRP_project.PRJ_bPluginsLoaded) then ( cbStart obstr.PVEHICLE_inst nil nil nil nil obstr; 0; ) else ( setPluginInstanceCbAllPluginsLoaded inst mkfun2 @cbInitPlugs obstr; 0; ); ); ); 0;; fun IniPlug(file)= PlugRegister @newOb nil; setPluginEditor @dynamicedit; 0;;