Bwind

De DigiWiki.

// --------------------------------------------------------
// SAILING SCRIPT VERSION 1-37 BBK EDITION
// --------------------------------------------------------
// BWind Sailing Engine Release 1-37
// by Becca Moulliez - RELEASE June 2010 - GNU/GPL
// SAIL + APPARENT WIND
// refer to boat name for release :
// BOAT RELEASE-WIND ENGINE VERSION-LATEST UPDATE VERSION
// i.e : 1-1-1
// script based upon Kanker Greenacre's Flying Tako
//------------------------------------------------------
//            Please do not remove this header
//                Permitted Free Uses
//  - allowed to use in your personal boats. 
//  - allowed to use in boats you wish to sell or give away in second life.
//  - allowed to modify any part to your particular needs
//                Not Allowed Uses
// - not allowed to re-package and give away, or sell this script. 
// - not allowed to change a few lines of code then call this your own work
// - not allowed to take this to another platform or any use other than Second Life sailing without the express permission from Becca Moulliez 
// ======= End Header =========
 
// ----------------------------------------- START PROGRAMME ---
 
///////////////////////////////////////////////////////////////////////
// GLOBAL BOAT SETTINGS /////////////////////////////////////////////
// you don't want to modify these settings  unless specifically noted //////
/////////////////////////////////////////////////////////////////////
 
//version settings
string boatName="Becky's BBK ";   // Rename this according to your needs... 
string versionNumber="1-37-x";  // Release reference
 
//script module flags
integer CONTROLS_MODULE=1;
integer SAIL_MODULE=2;
 
//environment
vector wind;
float windAngle;
float absWindAngle;
float seaLevel;
 
//reused math variables
vector eulerRot;
vector currEuler;
rotation quatRot;
rotation currRot;
 
//boat variables
float zRotAngle;
vector fwdVec;
vector upVec;
vector leftVec;
float compass;
 
//heeling variables
float heelAngle;
float heelTorque;
float heelAdd;
 
//linear motion variables
float currSpeed;
vector groundSpeed=ZERO_VECTOR;
float spdFactor=0.0;
float leeway;
 
//angular motion variables
float rotSpeed;
float rotDelta;
vector eulerTurnLeft;
vector eulerTurnRight;
rotation quatTurnLeft=ZERO_ROTATION;
rotation quatTurnRight=ZERO_ROTATION;
 
//sail variables
integer sailingAngle;
integer currBoomAngle=0;
integer delta;
integer incr;
float optBoomAngle;
float trimFactor;
 
//spinnaker variables
integer spinAngle;
integer spindelta;
integer currSpinAngle=0;
integer SPIN_UP=FALSE;
integer CurJib;
integer CurSpin;
string Tack;
 
//performance constants - Standard defaults
 
float timerFreq=1.0;              //timer frequency, seconds (original paramer 1.5; check this if gets laggy)
integer sheetAngle=5;          //initial sheet angle setting
float maxWindSpeed=14.0; //used for heeling calculation (better leave this unchanged)
 
//miscellaneous settings
 
key owner;                  //boat owner 
key avatar;                 //avatar sitting at the helm
integer lock=FALSE;
integer ownerVersion=TRUE;
integer SAIL_UP=FALSE;
integer permSet=FALSE;
integer HUD_ON=TRUE;
string idStr;
integer numTouches=0;
integer sailing=TRUE;
float mpsToKts=1.944; //Metres per Second to Knots conversion
float convert=1.944;
string units=" Kts.";
integer showKnots=TRUE; //Yes we show speed in Knots...
float time;
float offset;
float theta;
integer msgTypeModeChange=40001;
integer modeBWind=0;
string helpString;
string visualAid;
vector hudcolour;
string currentString;
integer ADV_HUD=FALSE; //Advanced HUD off by default; set to TRUE to set on...
 
//linked parts - childprims declarations; the rootscript will send commands to childs when running...
//to work properly relevant prims MUST be renamed following the scheme below
 
integer JIB;
integer SAIL;
integer BOOM;
integer HUD;
integer CREWMAN; //this refers to the Crew Poseball in the cockpit...
integer POLE;  //NEW for Spinnaker
integer SPINNAKER; //NEW for Sinnaker
 
 
//general sailing parameters          
float ironsAngle=31;             //this is as close as the boat can sail to the wind
float slowingFactor=0.7;      //speed drops by this factor every timerFreq seconds if sailing into the wind
float leewayTweak=1.50;    //scales leeway (0=no leeway)
float rotTweak=0.8;           //scales boat turning rate
float speedTweak=1.0;     //DON'T touch this !!!!!!!!
 
//Apparent Wind parameters
vector tmpwind;
float truewindDir;
float truewindSpeed;
float truewindAngle;
float appwindSpeed;
float appwindAngle;
 
// ------------------------- END GLOBAL BOAT SETTINGS ---
 
///////////////////////////////////////////////////////
// BWIND DEFAULT PRESET DECLARATION //////////////////
// modify this section as per 15 Knots Wind Preset //
////////////////////////////////////////////////////
 
//The boat will sail a 15 Knots East BWind by default... following parameters apply
 
float windDir=0; //BWind Wind direction 
string windRose="East ";   //BWind Preset declaration for 15 Knots Wind
string windType="15 Knots";     //BWind Preset declaration for 15 Knots Wind
 
//primary parameters
float windSpeed=7.75; // Don't touch this... 15 Knots Speed
float maxSpeed=5.5;   // Edit this according to your needs... this is the actual Speed with a 15 Knots Wind
float heelTweak=0.85; // Edit this according to your needs... this is the actual Heel for a 15 Knots Wind
 
//Note : you MUST check the 15 Knots BWind Preset below in the Script (line 829); The values set here MUST be the same...
 
// --------------------------- END DEFAULT PRESET DECLARATION ---
 
///////////////////////////////////////////////////
// GLOBAL BOAT EQUATIONS AND FUNCTIONS ///////
// you don't want to modify these settings //////
////////////////////////////////////////////////
 
//Following Equations and Functions will affect GLOBAL Boat's behavior -- I strongly recommend you will NOT edit unless you know what you are doing...
 
 
// BWind Basic Boat Behaviour - LSL Angle Calculation
 
integer realAngle2LslAngle(integer realAngle) { 
    integer lslAngle= (realAngle-90)*-1; 
    while(lslAngle>=360) lslAngle-=360; 
    while(lslAngle<0) lslAngle+=360; 
    return lslAngle; 
} 
 
//  BWind Basic Boat Behaviour - calculate wind angle
 
//TRUE WIND - True Wind has been left as a separate routine in case you dont want your boat to support Apparent Wind
calcTrueWindAngle() { 
    currRot=llGetRot(); 
    currEuler=llRot2Euler(currRot); 
    zRotAngle=currEuler.z;//boat heading 
    leftVec=llRot2Left(currRot); 
    truewindAngle=windDir-zRotAngle; 
    while (truewindAngle>PI) truewindAngle-=TWO_PI;     //bw -PI and PI 
    while (truewindAngle<-PI) truewindAngle+=TWO_PI;    //bw -PI and PI
    if ((truewindAngle) < 0) {
        truewindAngle = truewindAngle * -1;
    } 
}
 
//APPARENT WIND
calcAppWindAngle() { 
    currRot=llGetRot(); 
    currEuler=llRot2Euler(currRot); 
    zRotAngle=currEuler.z;  //boat heading 
    leftVec=llRot2Left(currRot); 
    windAngle=windDir-zRotAngle;
    while (windAngle>PI) windAngle-=TWO_PI;     //bw -PI and PI 
    while (windAngle<-PI) windAngle+=TWO_PI;    //bw -PI and PI 
    vector boatMovement=<currSpeed*llCos(currEuler.z),currSpeed*llSin(currEuler.z),0>;
    tmpwind=wind+boatMovement;
    float spd=llVecMag(llGetVel());
    appwindAngle=llAtan2(windSpeed*llSin(windAngle),(windSpeed*llCos(windAngle)+spd));
    while (appwindAngle>PI) spd=-spd;
    while (appwindAngle<-PI) spd=-spd;
    appwindSpeed=spd*llCos(llFabs(windAngle))-windSpeed*llCos(windAngle);
    if ((appwindSpeed) < 0) {
        appwindSpeed = appwindSpeed * -1;
    }
    if ((appwindSpeed) > 3) {
        appwindSpeed = appwindSpeed -(TWO_PI-1.0);
    }
    if ((appwindAngle) < 0) {
        appwindAngle = appwindAngle * -1;
    }
}
 
//  BWind Basic Boat Behaviour - calculate heel angle based on wind and sail settings
 
calcHeelAngle() {
    heelAngle=llAsin(leftVec.z);
    if (SAIL_UP)
        if (llFabs(windAngle+sailingAngle)>3*DEG_TO_RAD)
            heelTorque=SAIL_UP*llSin(windAngle)*llCos(heelAngle)*PI_BY_TWO*(windSpeed/maxWindSpeed)*llCos(sailingAngle*DEG_TO_RAD)*heelTweak;
        else heelTorque=0;
    else heelTorque=0;
    heelAdd=heelTorque-heelAngle;
    eulerRot=<heelAdd,0,0>;
    quatRot=llEuler2Rot(eulerRot);
}
 
//  BWind Basic Boat Behaviour - calculate angle of sail (or jib) based on sheet setting and the wind
 
calcBoomDelta() {
    if (sheetAngle<=0) sheetAngle=5; //never let the actual sheetangle be less than 5°
    if (sheetAngle>=79) sheetAngle=79; //never let the actual sheetangle be more than 79°
    sailingAngle=sheetAngle;
    if (sailingAngle>llFabs(windAngle*RAD_TO_DEG)) sailingAngle=llRound(llFabs(windAngle*RAD_TO_DEG));
    if (windAngle<0) sailingAngle*=-1;
    delta=sailingAngle-currBoomAngle;
    currBoomAngle=sailingAngle;
    if (currBoomAngle < 0) Tack="Starb'd";
    if (currBoomAngle > 0) Tack="Port";
    currBoomAngle=sailingAngle;
    llMessageLinked(SAIL,delta,"",NULL_KEY);//tell sail to rotate by delta
    llMessageLinked(JIB,delta,"",NULL_KEY);//tell jib to rotate by delta
    llMessageLinked(BOOM,delta,"",NULL_KEY);//tell boom to rotate by delta
}
 
//  BWind Basic Boat Behaviour - calculate boat speed
 
calcSpeed() {
    groundSpeed=llGetVel();
    absWindAngle=llFabs(windAngle);
    if (llFabs(absWindAngle*RAD_TO_DEG-llFabs(sailingAngle))<10) trimFactor=0;
    else {
        optBoomAngle=0.5*absWindAngle*RAD_TO_DEG;
        trimFactor=(90.-llFabs(optBoomAngle-llFabs(sailingAngle)))/90.;
    }
    //(old)if (absWindAngle<ironsAngle*DEG_TO_RAD) currSpeed*=slowingFactor;
    if (appwindAngle<ironsAngle*DEG_TO_RAD) currSpeed*=slowingFactor;
    else {
        if (SAIL_UP) {
            //currSpeed=speedTweak*(llCos(windAngle/2.)+0.5)*windSpeed*trimFactor;
            //if (currSpeed>maxSpeed) currSpeed=maxSpeed;
            currSpeed=speedTweak*(llSin(llFabs(windAngle)/2)+llCos(llFabs(windAngle)/2.75) - 0.75)*windSpeed*trimFactor; // mod donated by Eta Carver
        }
        else currSpeed*=0.8;
    }
}
 
//  BWind Basic Boat Behaviour - calculate leeway (lateral drift) due to wind
 
calcLeeway() {
    leeway=SAIL_UP*-llSin(appwindAngle)*llSin(heelAngle)*windSpeed*leewayTweak;     
    //BUG found by Balduin Aabye - ty :))
}
 
 
//  BWind Basic Boat Behaviour - calculate turning rate based on current speed
calcTurnRate() {
    spdFactor=llVecMag(groundSpeed)/(maxSpeed);
    rotSpeed=0.5+(spdFactor)/2.0;
}
 
// String Conversions - automatically detect link nums for each named part - based upon original Tako parts names
 
getLinkNums() {
    integer i;
    integer linkcount=llGetNumberOfPrims();  
    for (i=1;i<=linkcount;++i) {
        string str=llGetLinkName(i);
        if (str=="jib") JIB=i;
        if (str=="sail") SAIL=i;
        if (str=="boom") BOOM=i;
        if (str=="pole") POLE=i;
        if (str=="spinnaker") SPINNAKER=i;
        if (str=="hud") HUD=i;
        if (str=="crewman") CREWMAN=i;
 
    }
}
 
// RAISE ROUTINE - raise sail: start timer
 
raiseSail() {
    SAIL_UP=TRUE;
    llOwnerSay("Ready to sail... ");
    llMessageLinked(SAIL,1002,"",NULL_KEY); // raise sail
    llMessageLinked(JIB,1002,"",NULL_KEY); // raise jib
    llMessageLinked(BOOM,1002,"",NULL_KEY); // move boom
    llMessageLinked(CREWMAN,1000,"",NULL_KEY); // hide crewman poseball
    llSetTimerEvent(timerFreq);
    llLoopSound("sailing", 1.0);       
 
} 
 
// LOWER ROUTINE - lower sail but leave physics on
 
lowerSail() {
    llOwnerSay("Lowering sails... ");
    llMessageLinked(SAIL,1000,"",NULL_KEY);//lower sail w/ reset
    llMessageLinked(JIB,1000,"",NULL_KEY);//lower jib w/ reset
    llMessageLinked(BOOM,1000,"",NULL_KEY);//stop boom w/ reset
    llMessageLinked(POLE,1000,"",NULL_KEY);//stop pole w/ reset
    llMessageLinked(SPINNAKER,1000,"",NULL_KEY); // drop and reset spinnaker
    sailingAngle = 0;
    llStopSound();
    llMessageLinked(LINK_ALL_CHILDREN , 0, "stop", NULL_KEY); // stop all children-linked activities
    currBoomAngle=0;
    sheetAngle=5;
    SAIL_UP=FALSE; 
    llSetObjectDesc ("BWind Builder's Kit - Keelboat"); //This sets your boat's description string when lowering... useful when you add a WWC Wind routine
}
 
//SPINNAKER ROUTINE
HoistSpin(){
    if ((sheetAngle > 50)) {
        llOwnerSay("Hoisting Spinnaker");
        llMessageLinked(SPINNAKER,1002,"",NULL_KEY); //hoist spinnaker
        if (-sailingAngle > 0) llMessageLinked(POLE,1002,"",NULL_KEY);
        if (-sailingAngle < 0) llMessageLinked(POLE,1004,"",NULL_KEY);
        llMessageLinked(JIB,1001,"",NULL_KEY); //lower jib
        SPIN_UP=TRUE;
        CurJib=0;
    }
    if ((sheetAngle < 50)) {
        llOwnerSay("Sheet too close to Hoist Spin");
    }
}
DropSpin(){
    llOwnerSay("Dropping Spinnaker");
    llMessageLinked(SPINNAKER,1000,"",NULL_KEY); //drop spinnaker/W reset
    llMessageLinked(POLE,1000,"",NULL_KEY); // hide & reset pole
    llMessageLinked(JIB,1002,"",NULL_KEY); //raise jib
    CurSpin=0;
    CurJib=0;
    currSpinAngle=0;
    spinAngle=0;
    SPIN_UP=FALSE;
}
TrimSpinPlus() {
    if (CurSpin < 37) {
        llMessageLinked(SPINNAKER,(delta+3),"",NULL_KEY); //trim spinnaker +
        llMessageLinked(POLE,(delta+3),"",NULL_KEY); // hide pole
    CurSpin=CurSpin+3;
    } 
 
}
TrimSpinMinus() {
    if (CurSpin > -37) {
        llMessageLinked(SPINNAKER,(delta-3),"",NULL_KEY); //trim spinnaker -
        llMessageLinked(POLE,(delta-3),"",NULL_KEY); // hide pole 
        CurSpin=CurSpin-3;
    }
}
 
// VEHICLE PHYSICS PARAMETERS - set initial vehicle parameters
 
// WARNING !!!! - Following physics parameters should NOT be edited unless you REALLY KNOW what you are doing....
 
setVehicleParams() {
    //vehicle flags
    llSetVehicleType         (VEHICLE_TYPE_BOAT);
    llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME,ZERO_ROTATION); // ZERO_ROTATION = <0.0,0.0,0.0,1.0> you may wish to edit this for fun
    llSetVehicleFlags        (VEHICLE_FLAG_NO_DEFLECTION_UP|VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT|VEHICLE_FLAG_LIMIT_MOTOR_UP ); 
    //linear motion
    llSetVehicleVectorParam  (VEHICLE_LINEAR_FRICTION_TIMESCALE,<50.0,2.0,0.5>);;
    llSetVehicleVectorParam  (VEHICLE_LINEAR_MOTOR_DIRECTION,ZERO_VECTOR);
    llSetVehicleFloatParam   (VEHICLE_LINEAR_MOTOR_TIMESCALE,10.0);
    llSetVehicleFloatParam   (VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE,60);
    llSetVehicleFloatParam   (VEHICLE_LINEAR_DEFLECTION_EFFICIENCY,0.85);
    llSetVehicleFloatParam   (VEHICLE_LINEAR_DEFLECTION_TIMESCALE,1.0); 
    //angular motion
    llSetVehicleVectorParam  (VEHICLE_ANGULAR_FRICTION_TIMESCALE,<5,0.1,0.1>);
    llSetVehicleVectorParam  (VEHICLE_ANGULAR_MOTOR_DIRECTION,ZERO_VECTOR);
    llSetVehicleFloatParam   (VEHICLE_ANGULAR_MOTOR_TIMESCALE,0.1);
    llSetVehicleFloatParam   (VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE,3);
    llSetVehicleFloatParam   (VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY,1.0);
    llSetVehicleFloatParam   (VEHICLE_ANGULAR_DEFLECTION_TIMESCALE,1.0);//default 1.0 -- reduce to have more lateral drift (like 0.3 - 0.5)
    //vertical attractor
    llSetVehicleFloatParam   (VEHICLE_VERTICAL_ATTRACTION_TIMESCALE,3.0);
    llSetVehicleFloatParam   (VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY,0.8);
    //banking
    llSetVehicleFloatParam   (VEHICLE_BANKING_EFFICIENCY,0.0);
    llSetVehicleFloatParam   (VEHICLE_BANKING_MIX,1.0);
    llSetVehicleFloatParam   (VEHICLE_BANKING_TIMESCALE,1.2);
    //vertical control
    llSetVehicleFloatParam   (VEHICLE_HOVER_HEIGHT,seaLevel);
    llSetVehicleFloatParam   (VEHICLE_HOVER_EFFICIENCY,2.0);
    llSetVehicleFloatParam   (VEHICLE_HOVER_TIMESCALE,1.0);
    llSetVehicleFloatParam   (VEHICLE_BUOYANCY,1.0);
}
 
//MASTMAN AND CREW CAMERA SETUP - set camera position for third person view
 
setCamera() {
    llSetCameraEyeOffset(<-5.4,0.0,1.4>); //Here you may set your Sailing Camera EYE Offset
    llSetCameraAtOffset(<3.0,0.0,1.0>);    //Here you may set your Sailing Camera actual position
}
 
//REZZING INITIAL POSITION - figure out where to put boat when it is rezzed
// The boat will float at a 20.100 level... Edit and raise/lower the rootprim to set your waterline... DON'T mod THIS !
setInitialPosition() {
    vector pos=llGetPos();
    float groundHeight=llGround(ZERO_VECTOR);
    float waterHeight = llWater(ZERO_VECTOR);
    seaLevel=llWater(ZERO_VECTOR);
    upright();
    //if over water, set boat height to sealevel + 0.1m; this is the standard default water level
    if (groundHeight <= waterHeight) {
        pos.z = waterHeight + 0.1; //fixed by Balduin Aabye (originally 0.12)
        while (llVecDist(llGetPos(),pos)>.001) llSetPos(pos);
    }
}
 
//SIT TARGET - REFER TO pose_s SCRIPT FOR MASTMAN AND CREW SET - set sit target for helmsperson
//this function is now being disabled - there is an external pose script to set this...
 
setSitTarget() {
    llSetSitText("Sail !");
    llSetText("",ZERO_VECTOR,1.0);
}
 
//BOAT UPRIGHT POSITION - force boat upright
 
upright() {
    currRot=llGetRot();
    currEuler=llRot2Euler(currRot);
    leftVec=llRot2Left(currRot);
    heelAngle=llAsin(leftVec.z);
    eulerRot=<-heelAngle,0,0>;
    quatRot=llEuler2Rot(eulerRot);
    llRotLookAt(quatRot*currRot,0.2,0.2);
}
 
//MOORING FUNCTION - what happens when your boat moors...
 
moor() {
    llMessageLinked(LINK_THIS,SAIL_MODULE,"moor",NULL_KEY);
    {
        llSetTimerEvent(timerFreq);
        sailing=TRUE;
    }
    llOwnerSay("Mooring.");
    upright();
    llReleaseControls();
    llSetStatus(STATUS_PHYSICS,TRUE);
    llSetTimerEvent(0);
    currSpeed=0;
}
 
//GENERAL BOAT STARTUP - reset stuff - this resets the script to defaults... you may call this function as needed...
 
startup() {
    owner=llGetOwner();
    llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Z | STATUS_ROTATE_Y,TRUE);
    llSetStatus(STATUS_PHYSICS,FALSE);
    llSetStatus(STATUS_PHANTOM,FALSE);
    llSetStatus(STATUS_BLOCK_GRAB,TRUE);
    llSetTimerEvent(0);
    setInitialPosition();
    setVehicleParams();
    setSitTarget();
    getLinkNums();                               
    llMessageLinked(SAIL,1000,"",NULL_KEY);     //reset MAINSAIL
    llMessageLinked(JIB,1000,"",NULL_KEY);      //reset JIB
    llMessageLinked(BOOM,1000,"",NULL_KEY);      //reset BOOM
    llMessageLinked(CREWMAN,1001,"",NULL_KEY); // show crewman poseball
    llMessageLinked(POLE,1000,"",NULL_KEY); // hide & reset pole
    llMessageLinked(SPINNAKER,1000,"",NULL_KEY); //reset SPINNAKER
    setCamera(); //apply Camera default setting
    currSpeed=0;
    llListen(0,"",owner,""); //listen to boat owner only...
    llOwnerSay("Ready.");
    llMessageLinked(LINK_ALL_CHILDREN , 0, "stop", NULL_KEY);
}
 
// ------------------------------------- END GLOBAL BOAT EQUATIONS AND FUNCTIONS---
 
///////////////////////////////////////////////////
// HUD SETTINGS //////////////////////////////////
// you don't want to modify these settings //////
////////////////////////////////////////////////
 
// UPDATE HUD - Main HUD routine and colour management
updateHUD() {
    string dataString;
    float compass=PI_BY_TWO-zRotAngle;
    float effcoeff;
 
    string rgn = llGetRegionName();
    string blank = " ";
    float efficiency;
    string ratio;
    float derivatesheetAngle=sheetAngle;
 
    //CALCULATE SPINNAKER EFFECTS ON EFFICIENCY
 
    //Spinnaker tweak weighs 1/3 of global sheet
    if (Tack=="Starb'd") {
        derivatesheetAngle+=(CurSpin/3); //Starboards Spinnaker Tweak
    }
    if (Tack=="Port") {
        derivatesheetAngle-=(CurSpin/3); //Port Spinnaker Tweak
    }
 
    //ACTUAL EFFICIENCY CALCULATION including spinnaker tweaks
    efficiency = appwindAngle*RAD_TO_DEG/derivatesheetAngle;
    if ((efficiency) < 0) {
        efficiency = efficiency * -1;
    }
 
    compass=PI_BY_TWO-zRotAngle;
    while (compass<0) compass+=TWO_PI;
    dataString = " "; //clean hud message on startup
    currentString = " "; //clean hud storage on startup
 
    //HUD COMPASS CONVERSION
 
    float hudcompass =((integer)(compass*RAD_TO_DEG));
    string huddirection;
    if ((hudcompass) <= 360) {    
        huddirection="North";
    }
    if ((hudcompass) <= 315) {    
        huddirection="Northwest";
    }
    if ((hudcompass) <= 275) {    
        huddirection="West";
    }
    if ((hudcompass) <= 230) {    
        huddirection="Southwest";
    }
    if ((hudcompass) <= 185) {    
        huddirection="South";
    }
    if ((hudcompass) <= 140) {    
        huddirection="SouthEeast";
    }
    if ((hudcompass) <= 95) {    
        huddirection="East";
    }
    if ((hudcompass) <= 50) {    
        huddirection="Northeast";
    }
    if ((hudcompass) <= 5) {    
        huddirection="North";
    }
 
    // STANDARD HUD STRING CONSTRUCTION ROUTINE
 
    if (ADV_HUD==FALSE) {
 
    // efficiency positive convert and ratio calculation
    if ((efficiency) < 0) {
        efficiency = efficiency * -1;
    }
    ratio = llGetSubString ((string)efficiency, 0, 3);
 
    vector hudcolour=<1.0,1.0,1.0>;                                                             //default hudcolour
    dataString+="-> "+huddirection+" ";                                                        //add a direction string
    dataString+="( " +(string)((integer)(compass*RAD_TO_DEG))+"° )\n ";                       //add compass degrees           
    dataString+="| "+visualAid+" | Speed "+llGetSubString((string)(llVecMag(groundSpeed*convert)),0,3)+units+"\n";   //add boat speed
    dataString+=(windType)+" "+(windRose)+"BWind\n";                                        //add BWind wind preset
 
   //trailing blanks
    dataString+=blank+"\n";
    dataString+=blank+"\n";
 
    }
 
    // ADVANCED HUD STRING CONSTRUCTION ROUTINE
 
    if (ADV_HUD==TRUE) {
 
    // efficiency positive convert
    if ((efficiency) < 0) {
        efficiency = efficiency * -1;
    }
 
    vector hudcolour=<1.0,1.0,1.0>;                                                             //default hudcolour
    dataString+="-> "+huddirection+" ";                                                        //add a direction string
    dataString+="( " +(string)((integer)(compass*RAD_TO_DEG))+"° )\n ";                       //add compass degrees             
    dataString+="| "+visualAid+" | Speed "+llGetSubString((string)(llVecMag(groundSpeed*convert)),0,3)+units+" - ";   //add boat speed
    dataString+=(windType)+" "+(windRose)+"BWind\n";                                        //add BWind wind preset
    dataString+="True Wind Angle " +(string)((integer)(truewindAngle*RAD_TO_DEG))+"° - ";  //add True Wind
    dataString+="App. Wind Angle " +(string)((integer)(appwindAngle*RAD_TO_DEG))+\n";   //add Apparent Wind   
    ratio = llGetSubString ((string)efficiency, 0, 3);                                   //display efficiency conversion
    dataString+="Wind/Sheet ratio " +ratio+ " - Sheet Angle "+((string)(sheetAngle))+\n"; //add Efficiency and Sheet Angle
 
   //trailing blanks
    dataString+=blank+"\n";
    dataString+=blank+"\n";
 
 
    }
 
    //---------- END HUD CONSTRUCTION ROUTINE
 
    // HUD Colour Manager - This activates the HUD's virtual telltale function and affects ACTUAL BOAT'S SPEED WHILE TRIMMING
    // THIS ROUTINE IS VITAL FOR YOUR BOAT PERFORMANCE... THIS SETS THE BOAT'S SPEED WHEN YOU TRIM SAILS
 
    // too tight - cyan - this is good as it is...
    if ((efficiency) < 25.0) {    
        hudcolour=<0.0,1.0,1.0>;
        dataString==currentString; //update hud message on activation
        visualAid="<>"; //help symbol for colour visual impaired - immediate feel of TOO TIGHT
        speedTweak=0.3; //MODIFY THIS VALUE ACCORDING TO YOUR NEEDS... TWEAKS BOAT'S SPEED 
    }
 
    // optimal - green - INCREASE THIS (never over 3) for easier apparent wind sailing
    // LOWER THIS (never below 2) for a more demanding trim activity
    if ((efficiency) < 2.5) {   
        hudcolour=<0.0,1.0,0.0>;
        dataString==currentString; //update hud message on activation
        visualAid="="; //help symbol for colour visual impaired - immediate feel of OPTIMAL
        speedTweak=1.0; //MODIFY THIS VALUE ACCORDING TO YOUR NEEDS... TWEAKS BOAT'S SPEED
 
        //SPINNAKER Boost/De-Boost
        if (SPIN_UP==TRUE) {
            if ((sheetAngle < 65)) {
                speedTweak+=0.3;                
            }
            if ((sheetAngle > 65)) {
                speedTweak+=0.0;                
            }
            if ((sheetAngle < 50)) {
                speedTweak-=1.0; //original 0.5
                if (speedTweak < 0) speedTweak = 0.00001;
            }
        }  
    }
 
    // off optimal - yellow - here the sheet is too loose, but your boat will still sail quite well
    if ((efficiency) < 1.7) {    
        hudcolour=<1.0,1.0,0.0>;
        dataString==currentString; //update hud message on activation
        visualAid="><"; //help symbol for colour visual impaired - immediate feel of TOO LOOSE
        speedTweak=0.7; //MODIFY THIS VALUE ACCORDING TO YOUR NEEDS... TWEAKS BOAT'S SPEED 
    }
 
    // too loose - red - oh yes this is very bad... the boat will almost stop sailing :)
    if ((efficiency) < 1.2) {    
        hudcolour=<1.0,0.0,0.0>;
        dataString==currentString; //update hud message on activation
        visualAid=">><<"; //help symbol for colour visual impaired - immediate feel of WAY TOO LOOSE
        speedTweak=0.3; //MODIFY THIS VALUE ACCORDING TO YOUR NEEDS... TWEAKS BOAT'S SPEED 
    }
 
    //display hud string - HERE WE START HUD
    llSetText(dataString,hudcolour,1.0);
    currentString==dataString; //save current HUD message
 
    //Tacking animation management - HERE YOU CAN DECTIVATE THE TACKING ANIMATION - JUST COMMENT (//) THE FOLLOWING LINES 
    if (-sailingAngle > 0) {
        if ((llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) && llGetAgentSize(llGetPermissionsKey()) != ZERO_VECTOR) {
            llStopAnimation("bbk_helmsman");
            llStartAnimation ("bbk_helmstack");
        }
    }
    if (-sailingAngle < 0) {
        if ((llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) && llGetAgentSize(llGetPermissionsKey()) != ZERO_VECTOR) {
            llStopAnimation("bbk_helmstack");
            llStartAnimation ("bbk_helmsman");
        }
    }   
}
 
 
// ---------------------------- END HUD SETTINGS ---
 
//////////////////////////////////////////////////////////////////////////////////////////////
// SCRIPT TRAPPING ROUTINE - state default //////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
 
default {
 
    //get boat parts status
    state_entry() {
        getLinkNums();
        llSetText("",ZERO_VECTOR,1.0);
        startup();
        llSetStatus(STATUS_BLOCK_GRAB,TRUE);
    }
 
    //reset boat
    on_rez(integer param) {
        llResetScript();
    }
 
    //OWNER CHECK AND STATUS
    changed(integer change) {
        avatar=llAvatarOnSitTarget();
        if (change & CHANGED_LINK) {
            if (avatar==NULL_KEY) {
                if (!(llGetAgentInfo(owner) & AGENT_ON_OBJECT)) {
                    if (SAIL_UP) lowerSail();
                    if (permSet) llReleaseControls();
                    permSet=FALSE;
                    llMessageLinked(LINK_SET, 70400, "", NULL_KEY);
                    llResetScript();
                }
           }
           else {
                if (ownerVersion && avatar!=owner) llWhisper(0,"Only the owner can operate this boat.");
                else if ((llGetAgentInfo(owner) & AGENT_ON_OBJECT)) {
                    llWhisper(0,"Say raise to start sailing, help for sailing commands...");
                    llWhisper(0,"BWind System defaults to East Wind, 15 Knots...");
 
                    if (llAvatarOnSitTarget()==owner) llRequestPermissions(owner,PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION);          
                }
            }
        }
    }    
 
 
    //BOAT CONTROLS SETUP
    run_time_permissions(integer perms) {
        if (perms & (PERMISSION_TAKE_CONTROLS)) {
            llTakeControls(CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT |
            CONTROL_ROT_LEFT | CONTROL_FWD | CONTROL_BACK | CONTROL_DOWN | CONTROL_UP,TRUE,FALSE);
            permSet=TRUE;
            if (permSet) llStartAnimation("bbk_helmsman");
            llMessageLinked(LINK_SET, 70400, "", avatar); 
        }
    }
 
    // ------------------------ END STATE DEFAULT DECLARATIONS ---
 
    ////////////////////////////////////////////////////////////////////
    // MAIN BOAT LISTENER /////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////
 
    // YOU BETTER NEVER EDIT THE FOLLWING LINES UNLESS YOU KNOW WHAT TO DO :)
 
    listen(integer channel, string name, key id, string msg) {
        if (channel==0) {
            if (owner==id & llAvatarOnSitTarget()==owner) {
                if (llGetAgentInfo(owner) & AGENT_ON_OBJECT) {
                    if (llGetSubString(msg,0,4)=="sheet") {
                        incr=(integer)llDeleteSubString(msg,0,4);
                        sheetAngle+=incr;
                        if (sheetAngle>90) sheetAngle=90;
                    }
                    //MESSAGE raise - hey we DO want to sail huh?
                    else if (msg=="raise") {
                        llMessageLinked(LINK_ALL_CHILDREN , 0, "start", NULL_KEY);
                        sailing=TRUE;
                        if (!permSet) llRequestPermissions(owner,PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION);
                        permSet=TRUE;
                        llSetStatus(STATUS_PHYSICS,TRUE);
                        raiseSail();
                        llSetTimerEvent(timerFreq);
                    }
 
                    // SPINNAKER HOIST/DROP
                    else if (msg=="spin" && SPIN_UP) DropSpin();
                    else if (msg=="spin" && !SPIN_UP) HoistSpin();
 
                    //SPINNAKER TRIM
                    else if (msg=="spin+") TrimSpinPlus();
                    else if (msg=="spin-") TrimSpinMinus();
 
                    //GYBE POLE
                    else if (msg=="gybe") {
                        if (SPIN_UP==TRUE) {
                            llMessageLinked(SPINNAKER,1004,"",NULL_KEY); //hoist spinnaker
                            if (-sailingAngle > 0) llMessageLinked(POLE,1003,"",NULL_KEY);
                            if (-sailingAngle < 0) llMessageLinked(POLE,1004,"",NULL_KEY);
                            CurSpin=0;
                        }
                    }
 
                    //MESSAGE lower - okay now we want physics ON but no sailing...
                    else if (msg=="lower") lowerSail();
                    else if (msg=="moor") {
                        llMessageLinked(LINK_ALL_CHILDREN , 0, "stop", NULL_KEY);
                        moor();
                        llSetTimerEvent(0);
                        if (SAIL_UP) lowerSail();
                        llResetScript();
                    }
 
                    //BOAT ID Setter
                    else if (llGetSubString(msg,0,1)=="id") {
                        if (llGetSubString(msg,3,-1)!="off") {
                            idStr=llGetSubString(msg,3,-1);
                            string tmp=boatName+" #"+idStr;
                            llSetObjectName(tmp);
                            llWhisper(0,"New Boat ID :"+tmp);
                        }
                    }
 
                    //START bbk_helmsman ANIMATION
                    else if (llGetSubString(msg,0,3)=="anim") {
                        if (llGetSubString(msg,5,-1)=="off") {
                        }
                        else if (llGetSubString(msg,5,-1)=="on") {
                            if (permSet) llStartAnimation("bbk_helmsman"); // change thise pose/animation name if needed...
                        }
                    } 
 
                }
            }
 
            //-------------------------------- END MAIN BOAT LISTENER ---
 
            ///////////////////////////////////////////////////////////////
            // BWind Engine - WIND DIRECTION PRESETS /////////////////////
            //////////////////////////////////////////////////////////////
 
            //wind direction in degrees - North = 0°
            //you don't want to modify the following presets unless you want to add other BWind directions
 
            if (lock==FALSE) {
 
            if (msg=="n") {
                windRose ="North ";
                windDir=(90*DEG_TO_RAD);
                llWhisper(0,"BWind now blowing from North");
            }
            if (msg=="nw") {
                windRose ="Northwest ";
                windDir=(135*DEG_TO_RAD);
                llWhisper(0,"BWind now blowing from Northwest");
            }
            if (msg=="ne") {
                windRose ="Northeast ";
                windDir=(45*DEG_TO_RAD);
                llWhisper(0,"BWind now blowing from Northeast");
            }
            if (msg=="e") {
                windRose ="East ";
                windDir=(0*DEG_TO_RAD);
                llWhisper(0,"BWind now blowing from East");
            }
            if (msg=="s") {
                windRose ="South ";
                windDir=(270*DEG_TO_RAD);
                llWhisper(0,"BWind now blowing from South");
            }
            if (msg=="sw") {
                windRose ="Southwest ";
                windDir=(225*DEG_TO_RAD);
                llWhisper(0,"BWind now blowing from Southwest");
            }
            if (msg=="se") {
                windRose ="Southeast ";
                windDir=(315*DEG_TO_RAD);
                llWhisper(0,"BWind now blowing from Southeast");
            }
            if (msg=="w") {
                windRose ="West ";
                windDir=(180*DEG_TO_RAD);;
                llWhisper(0,"BWind now blowing from West");   
            }
 
            // ----------------------------- END WIND DIRECTION PRESETS ---
 
            ///////////////////////////////////////////////////////////////
            // BWind Engine - BWIND SPEED PRESETS ////////////////////////
            //////////////////////////////////////////////////////////////
 
            //this is where you have to mod to set your desired BWIND Wind PRESETS
            // REMEBER THAT THE BOAT SPEED IS SET IN THE TRIM/HUD ROUTINE ABOVE - here you set the max speed only for each wind preset...
            //You may add other wind speeds at will, while I think you have plenty...
            //WWC racing module preset will be added here upon release... (currently under development)
 
            //8 KNOTS PRESET
 
            if (msg=="8") {
                //primary parameters - self explanatory
                windSpeed=4.12; //PRECALCULATED WIND SPEED                 
                maxSpeed=4.0;    //YOUR BOAT MAX SPEED FOR THIS WIND PRESET 
                heelTweak=0.7;   //YOUR BOAT MAX HEEL FOR THIS WIND PRESET
 
                //Preset Boat Physics
                //llSetVehicleFloatParam   (VEHICLE_HOVER_HEIGHT,seaLevel);               //Vehicle Lift; this is useful for multihull boats
 
                //Preset running... return wind speed status... - THIS BUILDS THE HUD STRING....
                llWhisper(0,"BWind speed set to 8 Knots");
                windType="8 Knots"; // 8 Knots
            }
 
            // 11 KNOTS PRESET
 
            if (msg=="11") {
 
                //primary parameters - see above for explanation (8 Knots Preset)
                windSpeed=5.70;
                maxSpeed=4.5;
                heelTweak=0.8;
 
                //Preset Boat Physics
                //llSetVehicleFloatParam   (VEHICLE_HOVER_HEIGHT,seaLevel);               //Vehicle Lift
 
                //Preset running... return wind speed status...
                llWhisper(0,"BWind speed set to 11 Knots");
                windType="11 Knots"; // 11 Knots
            }
 
            // 15 KNOTS PRESET
            // VERY IMPORTANT !!!
            // REMEMBER ! : FOLLOWING VALUES MUST BE THE SAME YOU SET IN DEFAULT WIND SPEED AT LINE 143
 
            if (msg=="15") {
 
                //primary parameters - see above for explanation (8 Knots Preset)
                windSpeed=7.75;
                maxSpeed=5.5;
                heelTweak=0.85;
 
                //Preset Boat Physics
                //llSetVehicleFloatParam   (VEHICLE_HOVER_HEIGHT,seaLevel);               //Vehicle Lift
 
                //Preset running... return wind speed status...
                llWhisper(0,"BWind speed set to 15 Knots");
                windType="15 Knots"; // 15 Knots
            }
 
            // 18 KNOTS PRESET
 
            if (msg=="18") {
 
                //primary parameters - see above for explanation (8 Knots Preset)
                windSpeed=9.30;
                maxSpeed=6.5;
                heelTweak=0.95;
 
                //Preset Boat Physics
                //llSetVehicleFloatParam   (VEHICLE_HOVER_HEIGHT,seaLevel);               //Vehicle Lift
 
                //Preset running... return wind speed status...
                llWhisper(0,"BWind speed set to 18 Knots");
                windType="18 Knots"; // 18 Knots
            }
 
            // 21 KNOTS PRESET
 
            if (msg=="21") {
 
                //primary parameters - see above for explanation (8 Knots Preset)
                windSpeed=9.5;
                maxSpeed=7.0;
                heelTweak=1.0;
 
                //Preset Boat Physics
                //llSetVehicleFloatParam   (VEHICLE_HOVER_HEIGHT,seaLevel);               //Vehicle Lift
 
                //Preset running... return wind speed status...
                llWhisper(0,"BWind speed set to 21 Knots");
                windType="21 Knots"; // 21 Knots
            }
 
                        // 25 KNOTS PRESET
 
            if (msg=="25") {
 
                //primary parameters - see above for explanation (8 Knots Preset)
                windSpeed=11.3;
                maxSpeed=7.5;
                heelTweak=1.1;
 
                //Preset Boat Physics
                //llSetVehicleFloatParam   (VEHICLE_HOVER_HEIGHT,seaLevel);               //Vehicle Lift
 
                //Preset running... return wind speed status...
                llWhisper(0,"BWind speed set to 25 Knots");
                windType="25 Knots"; // 25 Knots
 
            }
 
            }
 
            // ------------------------------ END WIND SPEED PRESETS ---
 
 
            //////////////////////////////////////////////////////////////
            // UTILITIES ////////////////////////////////////////////////
            ////////////////////////////////////////////////////////////
 
            //Help Message
            //here you may build your own help message, shown when you type 'help' without quotes in chat...
 
            if (msg=="help") {
                helpString = " ";
                helpString+="SAY IN CHAT...\n";
                helpString+="------------------------------------------------------------------------------------------------\n";
                helpString+="raise - start sailing\n";
                helpString+="lower - lower sails (press arrow keys to move around)\n";
                helpString+="moor - stop sailing\n";
                helpString+="------------------------------------------------------------------------------------------------\n";
                helpString+="n,s,e,w,nw,ne,sw,se - set BWind direction\n";
                helpString+="8,11,15,18,21,25 - set BWind speed\n";
                helpString+="id nnaa (ex. 12AB) - set boat ID\n";
                helpString+="hud - hud switch (standard/advanced)\n";
                helpString+="spin - hoist/drop Spinnaker (press PgUp & PgDn to trim)\n";
                helpString+="gybe - gybe Spinnaker's pole upon tack\n";
                helpString+="------------------------------------------------------------------------------------------------\n";
                helpString+="HUD colour shows trim settings :\n";
                helpString+="|>><<| red = too loose - |><| yellow = off optimum - \n";
                helpString+="|=| green = optimum - |<>| cyan = too tight\n";
                helpString+="------------------------------------------------------------------------------------------------\n";
                llWhisper(0,helpString);
 
            }
 
            // HUD Switch -switch between the two alternative HUD modes : standard and advanced
 
            else if (msg=="hud" && ADV_HUD) ADV_HUD=FALSE;
            else if (msg=="hud" && !ADV_HUD) ADV_HUD=TRUE;
 
        }
    }    
 
    // --------------------------------------- END UTILITIES ---
 
    ///////////////////////////////////////////////////
    // GLOBAL BOAT CONTROLS //////////////////////////
    // you don't want to modify these settings //////
    ////////////////////////////////////////////////
 
    //Following section maps keyboard keys for boat control... I would NOT edit this section...
 
 
    control(key id, integer held, integer change) {
        //turning controls - LEFT AND RIGHT KEYS
        if ( (change & held & CONTROL_LEFT) || (held & CONTROL_LEFT) || (change & held & CONTROL_ROT_LEFT) || (held & CONTROL_ROT_LEFT) ) {
            if (sailing) llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<rotSpeed/2.0,0.0,rotSpeed>);
            else llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<-rotSpeed,0.0,rotSpeed/1.5>); // left key hold - end
        }
        else if ( (change & held & CONTROL_RIGHT) || (held & CONTROL_RIGHT) || (change & held & CONTROL_ROT_RIGHT) || (held & CONTROL_ROT_RIGHT) ) {
            if (sailing) llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<-rotSpeed/2.0,0.0,-rotSpeed>);
            else llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<rotSpeed,0.0,-rotSpeed/1.5>); // right key hold - end
        }
        else if ( (change & ~held & CONTROL_LEFT) || (change & ~held & CONTROL_ROT_LEFT) ) {
            llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<0.0,0.0,0.0>); // left key touched - end
        }
        else if ( (change & ~held & CONTROL_RIGHT) || (change & ~held & CONTROL_ROT_RIGHT) ) {
            llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<0.0,0.0,0.0>); // right key touched - end
        }
        //sail/throttle controls - UP AND DOWN KEYS
        if ( (held & CONTROL_FWD) && (held & CONTROL_UP) ) {
            if (sailing) {
                sheetAngle+=7;
                if (sheetAngle>90) sheetAngle=90;     
            }
        } // up key hold - end
        else if ( (held & CONTROL_FWD) || (change & held & CONTROL_FWD) ) {
            if (sailing) {
                sheetAngle+=2;
                if (sheetAngle>90) sheetAngle=90;
                llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,<5.0,0.0,0.0>);    
            }
        } // up key touched - end
        else if ( (held & CONTROL_BACK) && (held & CONTROL_UP) ) {
 
            if (sailing) {
                sheetAngle-=7;
                if (sheetAngle<5) sheetAngle=5;   
            } else {
                currSpeed-=0.3;
                if (currSpeed<-2) currSpeed=-2;
                llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,<currSpeed,0,0>);
            }
        } // down key hold - end
        else if ( (held & CONTROL_BACK) || (change & held & CONTROL_BACK) ) {
            if (sailing) {
                sheetAngle-=2;
                if (sheetAngle<5) sheetAngle=5;
                llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,<-5.0,0.0,0.0>);           
            } else {
                currSpeed-=0.3;
                if (currSpeed<-2) currSpeed=-2;
                llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,<currSpeed,0,0>);
            }
        } // down key touched - end
 
         //PGUP/PGDN Spinnaker control
        else if (change & held & CONTROL_UP) {
            TrimSpinPlus();
        }
        else if (change & held & CONTROL_DOWN) {
            TrimSpinMinus();
        }
 
    }    
 
    // ------------------------------------- END GLOBAL BOAT CONTROLS ---
 
    ///////////////////////////////////////////////////
    // GLOBAL BOAT TIMER /////////////////////////////
    // you don't want to modify these settings //////
    ////////////////////////////////////////////////
 
    //IMPORTANT !!! THIS IS THE ACTUAL BOAT CYCLE INVOKING ALL SAILING ROUTINES
    //WHATEVER YOU DELETE HERE WILL AFFECT ACTUAL ENGINE BEHAVIOUR
    //HERE YOU MAY ADD YOUR OWN PERSONAL FUNCTIONS IF NEEDED AND YOU KNOW WHAT TO DO...
 
 
    link_message(integer from,integer to,string msg,key id) {
    }
 
    timer() {
        calcTrueWindAngle();
        calcAppWindAngle(); // invoke wind angle calculation routine
        if (SAIL_UP) calcBoomDelta(); // invoke sail trim calculation routine
        calcHeelAngle(); // invoke heel calculation routine
        calcSpeed(); // invoke speed calculation routine
        calcLeeway(); // invoke leeway calculation routine
        calcTurnRate(); // invoke turn rate routine
        if (HUD_ON) updateHUD(); // update hud on cycle
        llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,<currSpeed,leeway,0>); // boat linear movement
        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,<heelTorque,0.0,0.0>); // boat angular movement
    }
 
    // -------------------------------------- END GLOBAL BOAT TIMER ---
 
}
 
// ------------------------------------- END PROGRAMME -----------------------------------------------------------------------
Outils personnels
  • Cette page a été consultée 8 784 fois.
donate
Google Ads