This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

MOTORRAD SCRIPT für BULLET in OPENSIM
#1
MOTORRAD SCRIPT für BULLET Physik in OPENSIM   by Tron

Nachdem sich meine Bikescripte in Opensim verbreiten und ich mehrere positive Rückmeldungen über das angenehm präzise Fahrverhalten erhalten habe,
veröffentliche ich nun dieses Script hier im Forum unter fairen Bedingungen:

Es darf frei in Opensim verbeitet werden, aber nicht gegen Geld verkauft werden. Der Hinweis auf mich als Autor ist zu belassen.
Verkauf und Veröffentlichung in SL ist alleinig mir vorbehalten.

Mögen alle damit Spaß haben die gerne auf ihrer Sim biken wollen.

Das Script ist Fahrtechnisch ausgereift und fertig. Allerdings kann man Features noch hinzufügen.
Etliches ist bereits integriert was ich bei Nachfrage gesondert beschreiben werde.

Hier nun das Basis Script. Diese kommt in ein unsichtbares Root Prim. Die Form des Rootprims ist für die Fahrdynamik sehr wichtig. Früher habe ich bei Autos zu einen abgeschrägten Primwürfel geraten. Das ist aber nicht für ein gutes Motorrad zielführend. Minimum muss der Würfel von allen 4 Seiten abgeschrägt sein damit man sich in die Kurven legen kann. Besser ist ein Eiförmiges Mesh mit entsprechender Physik. Dieses ermöglicht sanftes in die Kurve legen.

Das Fahrzeug selber wird dann mit diesem "PhysikPrim" verlinkt, und zur Fahrzeit phantom.

Einige Features:

FAHREN:

- das Bike hat 5 Vorwärtsgänge, Leerlauf und Rückwärtsgang.
- es gibt Unterstützung für schnelle Schaltvorgänge.
  Bremst man bei hoher Geschwindigkeit schaltet das Bike einen Gang herab um besseres Fahrverhalten und höhere Beschleunigung zu erzielen.
- Fahrparameter ändern sich dynamisch in Abhängigkeit von Gang und Fahrtgeschwindigkeit.
  Dies gilt für Lenkung, Kurvenneigung, Spurtreue, Driften, Radhaftung sowie Aufsteigen des Vorderrades.
- Es gibt einen Leerlauf in dem das Bike nicht driftet. Auch wird in diesem Modus getankt.
- Im ersten Gang neigt das Bike zum Aufsteigen des Vorderrades wenn man Pfeil Links und Pfeil Rechts gleichzeitig drückt.
- Im ersten Gang driftet das Bike wenn Gasgeben und Lenken zusammen erfolgt. Dann Raucht auch das Hinterrad

FAHRERANIMATIONEN:
- Es wird pro Gang eine eigene Fahrer Animation unterstützt.

BENZINVERBRAUCH:
- Das Bike verbaucht je nach Fahrtgeschwindigkeit unterschiedlich Benzin.  Dafür habe ich euch ein Tankstellenscript mit erstellt.
  Der Sprittank sollte der Fahrzeuggröße angepasst sein. Für ein normales Motorrad hat sich als "vollertank" 600 bewährt.
  Die initiale Tankfüllung nach Scriptreset wird in "benzintank" festgelegt. Es kann ja sein das man frisch gerezzte Bikes erstmal 1/3 voll haben will damit anfangs getankt werden muss.
  Aktuell ist das Scritp beim Start auf vollen Tank eingestellt. Probiert aber mal 200 als "benzintank" aus.

PARKEN:
- Es gibt einen Parkmodus auf dem Seitenständer wenn ihr absteigt.

LICHT:
- es gibt Unterstützung für Bremslicht/Rücklicht.
- es gibt Unterstützung für einen Frontscheinwerfer.
- es gibt Unterstützung für einen optionalen Lichtkegel vor dem Fahrzeug zur Strassenbeleuchtung.
- die Einstellung der Paramater wird halbautomatisch unterstützt:
- das Script sucht sich selber die Linknummern heraus wenn ihr die entsprechenden Teile im Mesh folgendermaßen benennt: (auf Gross/Kleinschreibung achten)
"Bremslicht", "Scheinwerfer", "Lichtkegel", "Hinterrad".

Die zugehörigen Faces müsst ihr aber per Hand eintragen:
für Bremslicht in"bremslichtface" damit im Mesh die richtige Fläche leuchtet, und für Scheinwerfer in "frontlichtface".


Code:
// P318 Motorrad mit Renngetriebe für Simcrossing in Opensim 09 by Tron V50
// Stand 12.09.2021  V2.0
// unterstützt Hinterraddrift, Gangschaltung mit Leerlauf
// Partikel Textur vorladen auf Fahrzeugprim, damit diese sofort angezeigt wird

//==== FAHRZEUG CHARAKTERISTIKA VARIABLEN: ====


// MOTOR
float   bremskraft           = 6;                                                       // Kraft der Betriebsbremse. Größer bremst stärker
float   motorbremse          = 1.0;                                                     // Motorbremswirkung 1.0 gut, 2.0 weniger Bremswirkung für längerere Auslauf
list    getriebeliste        = [ -5 , 0.001, 15, 25, 35, 45, 55 ];                      // Maximalkraft & Geschwindigkeit des Motors je Gang [ -5 , 0, 15, 25, 35, 55, 70 ];
list    beschleunigungsListe = [1.0, 100.0 , 1.0, 3.0, 6.0, 10.0, 15.0];                // Beschleunigungsdauer des Motors bis maximaler Ganggeschwindigkeit. 1 = schnell [1.0, 100.0 , 1.0, 3.0, 6.0, 10.0, 15.0];
list    ganganimationListe = ["Bikerfahrer","Bikerfahrer","Bikerfahrer","Bikerfahrer","Bikerfahrer","Bikerfahrer","Bikerfahrer"];
list    gangListe = ["Rückwärts","Leerlauf","1. Gang","2. Gang","3. Gang","4. Gang","5. Gang"];


// LENKUNG
float   lenkansprechverhalten = 0.32;  // 0.32 REAKTIONSZEIT der LENKUNG 0.2 knackig, 0.3 medium, 0,4träge
float   lenkberuhgungszeit = 0.8;      // 0.50 NACHWIRKZEIT der LENKUNG  0.2++ sehr direkt // 0.5 gut // 1.2 träge
float   kurvenkraenkung;               // 3 - 6 für Motorrad wird dynamisch zugewiesen
float   einknicken = 4;
float   lenkradius = 4;                // Basiswirkung der Lenkung. größere Werte ermöglichen kleinerer Wendekreise. Wirkung wird dynamisch gesteuert: gut 4

integer racemode = TRUE;                // Zeigt Geschwindigkeit und Benzin an, und verbraucht Benzin
vector  sitzposition = < -0.690, 0.0, 1.65>;      // Sitzposition

// Linknummern des FAHRZEUGS werden automatisch ermittelt anhand LINKNAMEN. Faces manuell eingetragen
integer bremslichtlink;                 // Bremslicht
integer bremslichtface = ALL_SIDES;     // Face des Bremslichtes

integer frontlichtlink;                 // Frontscheinwerfer
integer frontlichtface = 6;             // Face des Frontscheinwerfer manuell eintragen
integer lichtkegellink;                 // Lichtkegelprims vor dem Bike
integer hinterradlink = 5;              // Linknummer des Hinterrades für Rauch

// TANKDIMENSIONIERUNG
float   vollertank  = 600;             // Voller Tank
float   benzintank  = 600;             // Initiale Tankfüllung
integer benzin;

//==== ENDE FAHRZEUG CHARAKTERISTIKA VARIABLEN ====
integer debug = TRUE;

// TANKEN
integer  listenhandle;                   // für Tanken
integer  channel = -1000;                // Fernbedienungs Kanal für Tankstelle

// GLOBALE VARIABLEN
key      biker;
integer  bikefahrt;
integer  gang;                                      // aktuell eingelegter Gang
float    antriebskraft;
integer  ganganzahl;
string   gangname;
string   animation;                                 // aktuell gespielte Animation


vector   vel;
float    fahrtgeschwindigkeit;                     // aktuelle Geschwindigkeit
float    fahrfaktor;                               // Hilfsvariable zur Rechenreduktion

integer  rechtslenk;
integer  linkslenk;
integer  bremslicht_ist_an;                         // aktueller Zustand


// RAUCH
integer rauchpartikelzahl = 1;                      // Anzahl Partikel pro Ausstoß und Prim
integer raddrift;                                   // aktueller Zustand
list    particle_parameters;

//==== E N D   G L O B A L   V A R I A B L E   D E C L A R A T I O N ====

// Ermitteln der aktuellen Linknummer anhand des Linknamens
integer getlink(string linkname)
{
    integer linknummer = llGetNumberOfPrims();
    do
    {   
        if (linkname == llGetLinkName(linknummer)) { return (linknummer);}
        linknummer--;
    }
    while (linknummer > 0);
    return (0);
}


rauchpartikel()                                     // Rauchpartikel Vorab initialisieren um in der Fahrschleife Zeit zu sparen
{
    particle_parameters =
        [         
           PSYS_SRC_TEXTURE, llGetInventoryName(INVENTORY_TEXTURE, 0),  // erste Textur aus Prim auslesen und nehmen
           PSYS_PART_START_SCALE,  <3.0000,3.00000,3.00000>,
           PSYS_PART_END_SCALE, <7.5,7.5,7.5>,
           PSYS_PART_START_COLOR, <0.2 , 0.2 ,0.2 >,
           PSYS_PART_END_COLOR, <0.4,0.4,0.4>,
           PSYS_PART_START_ALPHA, 0.75,
           PSYS_PART_END_ALPHA, 0.0,
           PSYS_SRC_BURST_PART_COUNT, rauchpartikelzahl,
           PSYS_SRC_BURST_RATE, 0.1, //0.3
           PSYS_PART_MAX_AGE, 2.0,
           PSYS_SRC_MAX_AGE,(float) 0.0,
           PSYS_SRC_PATTERN, 2,
           PSYS_SRC_BURST_SPEED_MIN, 1.0,
           PSYS_SRC_BURST_SPEED_MAX, 2.05,
           PSYS_SRC_BURST_RADIUS, 0.1,
           PSYS_SRC_ANGLE_BEGIN, (float) 0.08*PI,
           PSYS_SRC_ANGLE_END, (float) 0.08*PI,
           PSYS_SRC_ACCEL, <2,0,-.3>,
           PSYS_PART_FLAGS, (integer)( 0 | PSYS_PART_INTERP_COLOR_MASK | PSYS_PART_INTERP_SCALE_MASK | PSYS_PART_EMISSIVE_MASK )
         ];
}


hinterraddrift(integer raddriftenlassen)            // Durchdrehendes Hinterrad: Rauch Erzeugung und Fahrwerte ändern: an / aus
{
    raddrift = raddriftenlassen;
    if (raddrift)
    {
        llMessageLinked(LINK_SET, 10, "2", NULL_KEY);
        llLinkParticleSystem(hinterradlink, particle_parameters );
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY,0.1);   // SPURTREUE: starkes seitliches Driften des Hinterrades 0.2
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 40.00); // DRIFTZEIT: starkes Nachdriften des durchdrehenden Hinterrades 10.0
        lenkradius = 8;
    }
    else
    {
        llMessageLinked(LINK_SET, 10, "1", NULL_KEY);
        llLinkParticleSystem(hinterradlink, []);
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY,1.0);  // SPURTREUE: kein seitliches Driften des Hinterrades 1.0
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 1.0);  // DRIFTZEIT: wenig Nachdriften des Hinterrades 1.0
        lenkradius = 4;
    }
}


bikeausrichten(integer park)              // Richtet das Bike in Park und Fahr Positionen aus
{
    rotation bikerot =  llGetRot();
    if (park) llSetRot(<-0.4, bikerot.y, bikerot.z, PI>);    // Bike parken (<0.0, -0.20, bikerot.z, PI>);
    else llSetRot(<0.0, bikerot.y, bikerot.z, PI>);           // Bike fahren  
}


frontlicht(integer an)                     // Schaltet Frontlicht an oder aus
{
    // PRIM_POINT_LIGHT, TRUE, primcolor, fIntensity, fRadius, fFalloff ]
    if (an)
    {  
        llSetLinkPrimitiveParamsFast(frontlichtlink, [PRIM_GLOW, frontlichtface, 1.0]);
        llSetLinkPrimitiveParamsFast(lichtkegellink, [PRIM_POINT_LIGHT, TRUE, <1.0, 1.0, 1.0>, 1.0, 10.0, 0.20, PRIM_GLOW, ALL_SIDES, 0.05]);
        llSetLinkPrimitiveParamsFast(bremslichtlink, [PRIM_POINT_LIGHT, FALSE, <1.0, 0.0, 0.0>, 0.0, 0.0, 0.0, PRIM_GLOW, bremslichtface, 0.5]);
    }
    else
    {
        llSetLinkPrimitiveParamsFast(frontlichtlink, [PRIM_GLOW, frontlichtface, 0.0]);
        llSetLinkPrimitiveParamsFast(lichtkegellink, [PRIM_POINT_LIGHT, FALSE, <0.0, 0.0, 0.0>, 0.0, 0.0, 0.0, PRIM_GLOW, ALL_SIDES, 0.0]);
        llSetLinkPrimitiveParamsFast(bremslichtlink, [PRIM_POINT_LIGHT, FALSE, <1.0, 0.0, 0.0>, 0.0, 0.0, 0.0, PRIM_GLOW, bremslichtface, 0.0]);
    }
}


bremslicht(integer bremse)                // Schaltet Bremslicht an oder aus
{
    if (bremse) {llSetLinkPrimitiveParamsFast(bremslichtlink, [PRIM_POINT_LIGHT, TRUE, <1.0, 0.0, 0.0>, 1.0, 2.0, 0.5 , PRIM_GLOW, bremslichtface, 1.0]);}
    else {llSetLinkPrimitiveParamsFast(bremslichtlink, [PRIM_POINT_LIGHT, FALSE, <1.0, 0.0, 0.0>, 0.0, 0.0, 0.0, PRIM_GLOW, bremslichtface, 0.5]);}
    bremslicht_ist_an = bremse;
}


integer tankanzeige(integer funktion )
{
    if (funktion == 1)
    {
        string kmh = (string)llRound(fahrtgeschwindigkeit * 5);
        string rpm = (string)llRound(((fahrtgeschwindigkeit / llList2Float(getriebeliste, gang ))*7000)+600);
        if(gang < 2) rpm = "600";
        string liter = (string) llRound((benzintank / 50));
       
        if (benzintank < ( vollertank * 0.15))
            {
                if(benzintank > 0) { llSetText( kmh + " kmh \n Gang: "+ gangname + " rpm: "+ rpm +  "  \n Benzin: RESERVE " + liter +" Liter",<1,0,0>,1.0); return(TRUE);}
                else { benzintank = 0;  antriebskraft = 0; llSetText( kmh + " kmh \n Gang: "+ gangname + " rpm: 0  \n Benzin: TANK LEER " ,<1,0,0>,1.0); return(FALSE);}
            }
        else { llSetText( kmh + " kmh \n Gang: "+ gangname + " rpm: "+ rpm +  "  \n Benzin: " + liter +" Liter",<1,1,1>,1.0); return(TRUE);}
    }
    else {llSetText("",<0,0,0>,0.0); return(TRUE);}
}


init_engine()                            // Vorinitialisierung des Bikes
{
    bikefahrt = FALSE;
    ganganzahl = llGetListLength(getriebeliste);
    llSetSitText("Biker");
    llSitTarget(sitzposition, ZERO_ROTATION);
    llSetLinkPrimitiveParamsFast(LINK_ALL_CHILDREN, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_NONE]);
    // LINKNummern ermitteln anhand Namen der Links
    bremslichtlink = getlink("Bremslicht");
    frontlichtlink = getlink("Scheinwerfer");
    lichtkegellink = getlink("Lichtkegel");   // Lichtkegelprims vor Fahrzeug
    hinterradlink  = getlink("Hinterrad");
}


gangschaltung(string schalte)            // Gangumschaltung
{   
    string neueanimation;

    if (schalte == "Leerlauf") { gang = 1; llMessageLinked(LINK_SET, 10, "0", NULL_KEY); llMessageLinked(LINK_SET, 20, (string)0, NULL_KEY);} // in Leerlauf schalten
    else if (schalte == "Rückwärts") { gang = 0; llSleep(0.5); init_fahrercam(-45.0, 6.0); llMessageLinked(LINK_SET, 10, "-1", NULL_KEY); } // Rückwärts Gang einlegen
    else if (schalte == "Vorwärts") { gang = 2;  llSleep(0.5); init_fahrercam(0.0, 2.5); llMessageLinked(LINK_SET, 10, "1", NULL_KEY);}  // in 1. Gang schalten
    else if (schalte == "+") { gang += 1;}  // in höheren Gang schalten
    else { gang -= 1;}    // schalte in niedrigeren Gang

    antriebskraft = llList2Float(getriebeliste, gang);
    float drehmoment = llList2Float(beschleunigungsListe, gang);
    llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, drehmoment);
   
    neueanimation = llList2String(ganganimationListe, gang);
    gangname =  llList2String(gangListe , gang);
    benzin = tankanzeige(1);
   
    hinterraddrift(FALSE);
    if (neueanimation != animation) // Animationswechsel
        {
            llStopAnimation(animation);
            animation = neueanimation;
            llStartAnimation(animation);
        }
    if (gang == 1){ llSetTimerEvent(0.0);} else llSetTimerEvent(1.0);
}


// *** KAMERA EINSTELLEN
init_fahrercam(float angle, float distance)
{
    llSetCameraParams(
        [
            CAMERA_ACTIVE, 1,                 // 0=INACTIVE  1=ACTIVE
                CAMERA_BEHINDNESS_ANGLE, angle,   // (0 to 180) DEGREES
                CAMERA_BEHINDNESS_LAG, 1.3,       // (0 to 3) SECONDS  0.3
                CAMERA_DISTANCE, distance,        // ( 0.5 to 10) METERS 2.5
                CAMERA_PITCH, 12.0,               // (-45 to 80) DEGREES
                CAMERA_POSITION_LOCKED, FALSE,    // (TRUE or FALSE)
                CAMERA_POSITION_LAG, 0.25,        // (0 to 3) SECONDS 0.05
                CAMERA_POSITION_THRESHOLD, 0.0,   // (0 to 4) METERS
                CAMERA_FOCUS_LOCKED, FALSE,       // (TRUE or FALSE)
                CAMERA_FOCUS_LAG, 0.0,            // (0 to 3) SECONDS
                CAMERA_FOCUS_THRESHOLD, 0.0,      // (0 to 4) METERS
                CAMERA_FOCUS_OFFSET, <0, 0, 0>    //  METERS
        ]);
    llForceMouselook(FALSE);
}


set_engine()
{
    llSetVehicleType(VEHICLE_TYPE_CAR);
   
     // default rotation of prim
        llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME, <0.00, 0.00, 0.00, 1.00>);
       
// VEHICLE FLAGS
        llSetVehicleFlags( VEHICLE_FLAG_NO_DEFLECTION_UP | VEHICLE_FLAG_HOVER_TERRAIN_ONLY);    // Fahrzeug Grundausrichtung bei falschen Mesh Axen
       

// LINEAR MOTOR ANTRIEB UND SPURTREUE
        llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 1.0);                // 1.0 BESCHLEUNIGUNG des MOTORS: Wirkung: Größere Zahl ergibt geringere Beschleunigung. 10 Gut für hohen Gang
        llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, motorbremse);  // 2.0 MOTORBREMSE: Wirkung: Kleinere Zahl größere Motorbremswirkung
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY,1.0);           // 1.0 SPURTREUE: bewirkt starkes seitliches driften des Hinterrades. 0.2 driftet stark für Start mit drehenden rauchenden Reifen, 0.5 leichtes driften. 1 fährt Spurtreu
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 1.00);           // 1.0 DRIFTZEIT nach Lenkstop: Kleine Zahl kurzes Nachdriften [1, .. , 100 ] Griffigkeit der Strasse simulierbar. 1trockener Asphalt, 100 Eis. 10 für Start mit drehenden rauchenden Reifen,

// ANGULAR MOTOR LENKUNG UND NEIGUNG BEI KURVEN
        llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, lenkansprechverhalten);     // REAKTIONSZEIT der LENKUNG
        llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, lenkberuhgungszeit);  // NACHLENKZEIT bis GERADEAUSLAUF
        llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 1.00);                // 1.0 SPURTREUE  wird dynamisch eingestellt
        llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 1.00);  // 1.00 DRIFTZEIT

// Friction Reibung
        llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE,  <1.0,1.0,1.0>  );  // ohne sichtbare Auswirkung <1.0,1.0,0.10>
        llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <1.0,1.0,1.0> );  // ohne sichtbare Auswirkung  <1.0,1.0,1.0>

// Vertical Attraction Vertikale Zugkraft
        llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 1.0);  // ohne sichtbare Auswirkung 5.5
        llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1.00);  // 1.0  FINAL sonst säuft Nase in Kurven ab // Werte <= 0.4 ZAPPELT Fahrzeug schlecht! SOLL1

// BANKING Nachschieben
        llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, 1.0 );
        llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, 0.5 );
        llSetVehicleFloatParam( VEHICLE_BANKING_MIX, 1.0 );
        llCollisionSound("", 0.0);
}


default
{
    state_entry()
    {
        if(!debug) llSetLinkTexture(LINK_THIS,llGetInventoryName(INVENTORY_TEXTURE, 0), ALL_SIDES);  // Partikeltextur auf roortprim vorladen damit sie sofort angezeigt wird
        bikeausrichten(TRUE);
        init_engine();
        rauchpartikel();
        llSetText("",<0,0,0>,0.0);
        state Fahrbereit;
    }
   
    on_rez(integer param) { llResetScript();}
}


state Fahrbereit
{
    state_entry() {}


    on_rez(integer param) { llResetScript();}


    changed(integer change)
    {
        if ((change & CHANGED_LINK) == CHANGED_LINK)
        {
            biker = llAvatarOnSitTarget();    // wir haben einen Fahrer
            if (biker != NULL_KEY)
                { llRequestPermissions(biker, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA | PERMISSION_TRACK_CAMERA);}
            else
            {   // Fahrer ist aufgestanden
                llMessageLinked(LINK_SET, 10, "0", NULL_KEY);  // Räder stoppen
                llSetTimerEvent(0.0);
                llSetStatus(STATUS_PHYSICS, FALSE);
                bikeausrichten(TRUE);
                bremslicht(FALSE);                 // Bremslicht ausschalten
                frontlicht(FALSE);
                bikefahrt = FALSE;
                llStopAnimation(animation);
                hinterraddrift(FALSE);
                llPushObject(biker, <3,3,21>, ZERO_VECTOR, FALSE);
                llReleaseControls();
                llClearCameraParams();
                llSetCameraParams([CAMERA_ACTIVE, 0]);
                benzin = tankanzeige(FALSE);
               // llResetScript(); // Hinderlich bei Benzinberechnung. Ansonsten gut
                llListenRemove(listenhandle);
                state default;
            }
        }
    }

    run_time_permissions(integer perm)
    {
        if (perm)
        {
            set_engine();                // MOTOR einstellen
            listenhandle = llListen(channel,"","","");
            bikeausrichten(FALSE);
            llSetStatus(STATUS_PHYSICS | STATUS_ROTATE_X | STATUS_ROTATE_Y | STATUS_ROTATE_Z, TRUE);
            frontlicht(TRUE);
            bikefahrt = TRUE; // BIKE fährt
            animation = "sit";
            gangschaltung("Leerlauf"); // im Leerlauf starten und Animation ändern
            benzin = tankanzeige(TRUE);
            init_fahrercam(0.0, 2.5);
            llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_DOWN | CONTROL_UP | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT, TRUE, FALSE);
            llSleep(1.5);
        }
    }


    control(key id, integer tastenzustand, integer tastenaenderung)
    {
        if(!bikefahrt){return;}
        vector AngularMotor;
       
        integer tastefrischgedrueckt = tastenzustand & tastenaenderung;   
        integer tastelosgelassen = ~tastenzustand & tastenaenderung;
     //     integer tastegehalten = tastenzustand & ~tastenaenderung;
     //     integer tastenichtgehalten = ~tastenzustand & ~tastenaenderung;

        vel = llGetVel();
        fahrtgeschwindigkeit = llVecMag(vel);            // Geschwindigkeit
        fahrfaktor = fahrtgeschwindigkeit /10;     // Hilfsvariable zur Rechenreduktion


// in höheren Gang schalten mit BILD AUF
        if(tastefrischgedrueckt & (CONTROL_UP | CONTROL_RIGHT)) { if (gang < (ganganzahl -1)) gangschaltung("+");}
// sonst in niedrigerne Gang schalten mit BILD AB
        else if(tastefrischgedrueckt & (CONTROL_DOWN | CONTROL_LEFT)) { if (gang > 0) gangschaltung("-");}


// weiterhin Vorwärts Gas geben
        if (tastenzustand & CONTROL_FWD)
        {
            if (gang < 2) gangschaltung("Vorwärts");        // Auf 1. Gang schalten wenn kein Vorwärtsgang eingelegt war
            else { llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft,0,0>);} // Linear Motor Kraft geben
           
// Sport Gangschaltung aufwärts
  //          if  ((tastefrischgedrueckt & CONTROL_ROT_RIGHT) && (tastefrischgedrueckt & CONTROL_ROT_LEFT))  { if (gang < (ganganzahl -1)) gangschaltung("+"); tastefrischgedrueckt = FALSE; tastenzustand = FALSE; llSleep(0.1); return; }
// Sport Gangschaltung abwärts
            if ((tastefrischgedrueckt & CONTROL_BACK)) {if (gang > 2) gangschaltung("-"); tastefrischgedrueckt = FALSE; tastenzustand = FALSE; llSleep(0.1); return; }
      
        }
// sonst Rückwärts schalten (nur wenn kein Gas gegeben wird, und Fahrzeug fast im Stillstand)
        else if (tastefrischgedrueckt & CONTROL_BACK) { if ((fahrtgeschwindigkeit < 0.5 ) && (gang > 0)) { gangschaltung("Rückwärts");}}

// weiterhin Rückwärts fahren oder Bremsen
        if (tastenzustand & CONTROL_BACK)
        {
            if (gang > 1)
            {
                if (!bremslicht_ist_an) bremslicht(TRUE);
                if(fahrtgeschwindigkeit > 9) {llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <-bremskraft, 0, 0>);} // stark Bremsen
                else llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0, 0, 0>);  // sanft Bremsen, Rückwärts fahren verhindern
            }
            else if (gang == 0) { llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft, 0, 0>);} // Rückwärts fahren
        }
// sonst Bremse lösen
        else if (tastelosgelassen & CONTROL_BACK){ if (bremslicht_ist_an) bremslicht(FALSE); llMessageLinked(LINK_SET, 20, (string)fahrtgeschwindigkeit, NULL_KEY);}


// Vorderrad Aufsteigen bei Vorwärtsfahrt und links + rechts Pfeiltasten
        if  ((tastenzustand & CONTROL_ROT_RIGHT) && (tastenzustand & CONTROL_ROT_LEFT))
        {
            if((gang == 2) || (gang == 3))                                    // nur im 1. und 2. Gang aufsteigen lassen
            {
                rechtslenk++; linkslenk++;                                     // eventuell rauchende Reifen erhalten
                AngularMotor.y -= ( 2.7 );                                     // Vorderrad aufsteigen lassen
                if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <5.0, 0, 0>); // Vortrieb falls zu langsam für Aufsteigen           
            }
        }
       
// RECHTS lenken
        if  (tastenzustand & CONTROL_ROT_RIGHT)
        {
           if( gang > 1)   // Einknicken in Kurvenmittelpunkt bei Vorwärtsfahrt
            {
                rechtslenk++;
                if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <3.0, 0, 0>); // Vortrieb falls zu langsam für Kurvenfahrt
                if ((rechtslenk > 30) & (gang == 2) & (fahrtgeschwindigkeit > 4.5)) { if (!raddrift) hinterraddrift(TRUE);}     // Hinterrad rotieren lassen
            }
            AngularMotor.y -= ( 1.15 );                                     // Nase hoch zur Kompensation des Eintauchens 0.75
            AngularMotor.x += ( einknicken + fahrfaktor );                   // Seitlich einknicken steigt mit Geschwindigkeit (3-6 gut)
            if(gang >0) AngularMotor.z -= ( lenkradius - fahrfaktor );        // Lenkung wird mit steigender Geschwindigkeit wirkungsloser
            else if(!gang) AngularMotor.z += 4;                                // Rueckwärts invers lenken
        }
// Nicht mehr rechts lenken
        else if (tastelosgelassen & CONTROL_ROT_RIGHT){ rechtslenk = 0; llMessageLinked(LINK_SET, 30, (string)0, NULL_KEY);}

// LINKS Lenken
        if (tastenzustand & CONTROL_ROT_LEFT)
        {
           if( gang > 1)  // Einknicken in Kurvenmittelpunkt bei Vorwärtsfahrt
            {
                linkslenk++;
                if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <3.0, 0, 0>); // Vortrieb falls zu langsam für Kurvenfahrt
                if ((linkslenk > 30) & (gang == 2) & (fahrtgeschwindigkeit > 4.5)) { if (!raddrift) hinterraddrift(TRUE);}      // Hinterrad rotieren lassen
            }
            AngularMotor.y -= ( 1.15 ); // Nase hoch zur Kompensation des Eintauchens
            AngularMotor.x -= ( einknicken + fahrfaktor );       // Seitlich einknicken steigt mit Geschwindigkeit (3-6 gut)           
            if(gang >0) AngularMotor.z += ( lenkradius - fahrfaktor );    // Lenkung wird mit steigender Geschwindigkeit wirkungsloser
            else if(!gang) AngularMotor.z -= 4;                            // Rueckwärts invers lenken
        }
// Nicht mehr links lenken
        else if (tastelosgelassen & CONTROL_ROT_LEFT){ linkslenk = 0;}

        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, AngularMotor);     // ROTATIONS MOTOR mit Kraft versorgen
        if ((!rechtslenk) & (!linkslenk) & raddrift) {hinterraddrift(FALSE);}        // rauchende Reifen abschalten
    }
   
   
    timer()
    {
        vel = llGetVel();
        fahrtgeschwindigkeit = llVecMag(vel);      // beide Richtugnen haben positive Geschwindigkeit!
        float verbrauch = fahrtgeschwindigkeit / 20;    // Hilfsvariable zur Rechenreduktion
        if(racemode)
        {   
            benzintank -= verbrauch;                  // Spritverbrauch
            benzin = tankanzeige(1);
        }
        if((gang != 1) & (fahrtgeschwindigkeit < 0.1)) { gangschaltung("Leerlauf"); fahrtgeschwindigkeit = 0.0;} // bei Stand in Leerlauf schalten
        llMessageLinked(LINK_SET, 20, (string)fahrtgeschwindigkeit, NULL_KEY);
    }


    listen(integer channel, string name, key id, string message)
    {
        string sender =  llGetSubString( message, 0, 35 );

        if(biker == sender)
        {
            float tankmenge =  ((vollertank - benzintank)/50);
            string befehl =  llGetSubString( message, 36, llStringLength( message ));
            if(befehl == "Tanken")
            {
                if(gang ==1)
                {
                    llWhisper(0, (string)tankmenge + "Liter Super getankt, das macht dann €:" + (string)(tankmenge *1.57));
                    benzintank = vollertank;
                    if(racemode) benzin = tankanzeige(1);
                }
                else {llWhisper(0, "Bitte zum Tanken den Motor abstellen");}
            }
        }
    }
}


Vorderrad und Hinterrad Script

In Vorder und Hinterrad kommt jeweils folgendes Radscript. Das Radscript dreht das verlinkte Radmesh direkt. Dazu muss die Achse des Rads passen.
Alternativ kann man hier auch die Achse im Script einstellen.   lltargetOmega <x,y,z>


Code:
// Radscript Variante by Tron
integer richtung = 0;
float   speed;

default
{
    state_entry()
    {
        llTargetOmega(<0,1,0>,PI,0.0);
    }

    link_message(integer sender_num,integer kanal,string message,key id)
    {
        if (kanal == 10) { richtung = (integer)(message);}
        else if (kanal == 20) { speed = (float)message * 0.20 *PI;}

        if ((richtung > 0) & (speed > 0.1)) llTargetOmega(<0,3,0>,speed,0.5);
        else if ((richtung < 0) & (speed > 0.1)) llTargetOmega(<0,-3,0>,speed,0.5);
        else { speed = 0; llTargetOmega(<0,0,0>,PI,0.0);}
    }
}


Tankstellen Script:

Das Tankstellenscript dient dem Betanken von mir gescripteter Fahrzeuge.
Das Script kommt in einen transparenten Primwürfel, der Phantom gemacht wird. Dieser soll die Zapfsäule großzügig ummanteln damit ein Klick auf die Zapfsäule das Prim trifft.

Getankt wird indem man auf dem Fahrzeug in Nähe der Zapfsäule sitzt,  den LEERLAUF eingelegt hat, und die Zapfsäule anklickt.
Dann muss man warten bis der Tankvorgang abgeschlossen ist. Nun erhält man eine Meldung wieviel getankt wurde.
Die Zapfsäule ist auch für alle anderen modernen Fahrzeuge meiner Entwicklung zu nutzen. Aktuell sind das Autos. Boote werden folgen.

Die Tankstelle funktioniert aktuell nur interaktiv mit meinen Fahrzeugen.
Wenn jemand seine Fahrzeugscripte in das Tanksystem integrieren will, bitte hier posten für Hilfe, oder aus dem Bike Script herauslesen

Code:
P319 Tankstelle Zapfsäulenscript by Tron V1.0

string ident = "Tanken";
integer channel = -1000;                // Fernbedienungs Kanal zur Kommunikation für Fahrzeuge
key user;                               // ID desjenigen der die Zapfsäule berührt- wird ans Fahrzeug gesendet
integer listenhandle;                   // für Tanken

default
{
    touch_end(integer num_detected)
    {
        user =  llDetectedKey(0);
        llSay (0, "Tankvorgang gestartet... bitte warten");
        listenhandle = llListen((channel+1),"","","");
        llSleep(20.0);
        llWhisper(channel,(string) user +ident);    // ID desjenigen der die Zapfsäule berührt- wird ans Fahrzeug gesendet
    }

    listen(integer channel, string name, key id, string message)
    {
        string sender =  llGetSubString( message, 0, 35 );
        if(user == sender)
        {
            string befehl =  llGetSubString( message, 36, llStringLength( message ));
            {
                llSay(0, befehl);
                llListenRemove(listenhandle);
            }
        }
    }
}


So, nun wünsche ich viel Spaß, und freue mich auf Rückmeldungen

Tron
Zitieren
#2
Erstklassig, hervorragender Beitrag!

LG

Lukas

Yes
All done!
Zitieren
#3
Danke Lukas!

Ich hab nun Zeit gefunden die Beschreibung zu vervollständigen.
Ich hatte für die Bikes auch eigene Mesh- Rennfahrbahnen erstellt.
Gerne kannst du Bike und Fahrbahnen bei mir bekommen.
Zitieren
#4
Lieber Tron

Ich habe dein Script heute mal frecherweise auf Herz und Nieren geprüft.
Ersteinmal muss ich sagen das fahrverhalten ist hervorragend alle eingebauten extras für jemanden der scripte lesen kann um das bike für dieses script fertig zu machen sind auch super. Tanken ist eine tolle Idee gerade für Bikersims.
Doch leider habe ich noch 2 Dinge die mich persönlich stören.
1. Leider finde ich nirgens die möglichkeit auf Owner only umzuschalten was schön wäre

2.Das für mich grösste Problem.
Wo sind die Sounds?
wenn man wie bei den sitzposen für jeden gang und für motor an beim aufsteigen und motor aus beim absteigen via sound uuid oder Soundname (wenn sounds mit im selben prim liegen) einsetzen kann und somit jeder sein bike individuell soundtechnich gestalten kann wäre es in meinen augen das beste Bikescript welches Open Sim jemals hatte.


falls du diese änderungen noch machen würdest, wäre ich über eine Rückmeldung erfreut...

Grüsse Moe und Stellabina
Zitieren
#5
Lieber Moe,

erstmal Danke für deine Rückmeldung, und ich freue mich das dir das Fahrverhalten zusagt.

Zu deinen Wünschen:

Punkt 1. ist in 5 Minuten zu erfüllen. Das dafür nötige Modul habe ich hier bereits veröffentlicht:

https://service-silberwelten.de/showthread.php?tid=145

Es ist ledilich der Aufrufpunkt im Bike Script festzulegen. Das kann ich mal für dich und Stellabina persönlich machen.
UPDATE 15.08.2022: Das habe ich in Version 3.0 gemacht die weiter unten in diesem Post anhängt

Die Sounds sind deswegen ein Problem weil ich Dinge - wenn ich sie anfasse- perfekt machen will.
Nur ein bissl Lärm einbauen ist schnell fertig, entspricht aber nicht meinem Anspruch.

Ich wollte etwas realistisches schaffen. Das bedeutet das Sounds Drehzahl und Last anhängig sein müssen.
Beschleunigung und Schalten muss man hören. Die Drehzahl muss dir die Schaltpunkte real hörbar machen.

Ich hab genau sowas als script für Autos in Arbeit, dort realisiere ich meinen RL Sportwagen virtuell.

Für die Sounds dieses Fahrzeuges habe ich mehr als eine Stunde Tonaufnahmen Rl gemacht,  bin gut 50km gefahren- offen und geschlosssen.
Diverse Fahrzyklen absolviert, Anlassen offen und geschlossen, Bescheunigen, und Fahren bei konstanten Drehzahlen, etc....
Die Einbindung ins Script ist teilweise realisiert, aber ich muss noch einige Tonaufnahmen bearbeiten. Das liegt nun aber wegen andere Projekte auf Eis.
Ist schlicht keine Cabrio Zeit im Moment, wenn ich zum Fenster raussehe.

Für Bikes steht das aktuell nicht auf meiner Wunschliste, obwohl ich in direkter Umgebung Rennfahrer wohnen habe,
die mir sicher mal Aufnahmen ermöglichen. Aber das Biken ist bei uns im Grid nun in den Hintergrund getreten.
Wir bauen aktuell Gothik und Sience Fiction.

Sollte sich das mal ändern werde ich ganz sicher an euch beide denken, und es dir zusenden. Grüsse mir bitte Stellabina!

Bis bald Tron
Zitieren
#6
Für diejenigen die zu Zweit biken wollen habe ich bereits eine Lösung gepostet:

https://service-silberwelten.de/showthread.php?tid=74

Das Script für den Beifahrer kommt samt der Animation am besten in einen zusätzlichen unsichtbaren Würfel rein der mit dem Bike verlinkt wird.

Und nicht die Spucktüte für die Beifahrer vergessen!

Gruß Tron
Zitieren
#7
Anbei ein Update des obigen Motorrad Scriptes auf Verison 3.01


Hauptänderung ist ein integriertes Berechtigungs System.

Wer das Bike nutzen darf ist nun einstellbar.
- Besitzer darf immer
- Bestimmte Avas anhand ihrer UUID
- Selbe Gruppe
- oder Jeder

Code:
// P318 Motorrad mit Renngetriebe für Simcrossing in Opensim 09 by Tron
// Stand 24.08.2022  V3.01
// unterstützt Hinterraddrift, Gangschaltung mit Leerlauf
// verbaucht Benzin und zeigt Fahrwerte an im Racemodus
// Partikel Textur vorladen auf Fahrzeugprim, damit diese sofort angezeigt wird
// V3.01 Änderung der Funktion Tankanzeige um Division durch Zero Fehler in 0.9.2.1 zu verhindern.

// Version 3.0 enthält Berechtigung Check. Festlegen wer rein darf: Der Besitzer darf immer.
// zusätzlich Personenbezogene Berechtigung anhand der AVA UUID
list    zugangsliste = ["b6a520ac-a468-4bc3-9e52-b509e88a8bce","18da7264-3260-4b63-8173-2a6fd7e93e33"]; // UUIDS berechtigter AVAs

// Öffentlicher Zugang erlaubt?
integer publicaccess = FALSE;   // Darf jeder das Fahrzeug nutzen? [TRUE/FALSE]

// GRUPPENZUGANG erwünscht?
integer groupaccess = TRUE;     // Dürfen Mitglieder der selben Gruppe das Fahrzeug nutzen? [TRUE/FALSE]


//==== FAHRZEUG CHARAKTERISTIKA VARIABLEN: ====


// MOTOR
float   bremskraft           = 6;                                                       // Kraft der Betriebsbremse. Größer bremst stärker
float   motorbremse          = 1.0;                                                     // Motorbremswirkung 1.0 gut, 2.0 weniger Bremswirkung für längerere Auslauf
list    getriebeliste        = [ -5 , 0.001, 15, 25, 35, 45, 55 ];                      // Maximalkraft & Geschwindigkeit des Motors je Gang [ -5 , 0, 15, 25, 35, 55, 70 ];
list    beschleunigungsListe = [1.0, 100.0 , 1.0, 3.0, 6.0, 10.0, 15.0];                // Beschleunigungsdauer des Motors bis maximaler Ganggeschwindigkeit. 1 = schnell [1.0, 100.0 , 1.0, 3.0, 6.0, 10.0, 15.0];
list     ganganimationListe = ["Bikerfahrer","Bikerfahrer","Bikerfahrer","Bikerfahrer","Bikerfahrer","Bikerfahrer","Bikerfahrer"];
list     gangListe = ["Rückwärts","Leerlauf","1. Gang","2. Gang","3. Gang","4. Gang","5. Gang"];


// LENKUNG
float   lenkansprechverhalten = 0.32;  // 0.32 REAKTIONSZEIT der LENKUNG 0.2 knackig, 0.3 medium, 0,4träge
float   lenkberuhgungszeit = 0.8;      // 0.50 NACHWIRKZEIT der LENKUNG  0.2++ sehr direkt // 0.5 gut // 1.2 träge
float   kurvenkraenkung;               // 3 - 6 für Motorrad wird dynamisch zugewiesen
float   einknicken = 4;
float   lenkradius = 4;                // Basiswirkung der Lenkung. größere Werte ermöglichen kleinerer Wendekreise. Wirkung wird dynamisch gesteuert: gut 4

integer racemode = TRUE;            // Zeigt Geschwindigkeit und Benzin an, und verbraucht Benzin
vector  sitzposition = < -0.690, 0.0, 1.65>;      // Sitzposition

// Linknummern des FAHRZEUGS werden automatisch ermittelt anhand LINKNAMEN. Faces manuell eingetragen
integer bremslichtlink;                 // Bremslicht
integer bremslichtface = ALL_SIDES;     // Face des Bremslichtes

integer frontlichtlink;                 // Frontscheinwerfer
integer frontlichtface = 6;             // Face des Frontscheinwerfer manuell eintragen
integer lichtkegellink;                 // Lichtkegelprims vor dem Bike
integer hinterradlink = 5;              // Linknummer des Hinterrades für Rauch

// TANKDIMENSIONIERUNG
float   vollertank  = 600;              // Voller Tank
float   benzintank  = 600;              // Initiale Tankfüllung
integer benzin;

//==== ENDE FAHRZEUG CHARAKTERISTIKA VARIABLEN ====
integer debug = FALSE;                  // DEBUGMODUS zur Fehlersuche und Entwicklung

// TANKEN
integer  listenhandle;                  // für Tanken
integer  channel = -1000;               // Fernbedienungs Kanal für Tankstelle

// GLOBALE VARIABLEN
key      biker;
integer  access;
integer  bikefahrt;
integer  gang;                          // aktuell eingelegter Gang
float    antriebskraft;
integer  ganganzahl;
string   gangname;
string   animation;                     // aktuell gespielte Animation


vector   vel;
float    fahrtgeschwindigkeit;          // aktuelle Geschwindigkeit
float    fahrfaktor;                    // Hilfsvariable zur Rechenreduktion

integer  rechtslenk;
integer  linkslenk;
integer  bremslicht_ist_an;             // aktueller Zustand


// RAUCH
integer rauchpartikelzahl = 1;          // Anzahl Partikel pro Ausstoß und Prim
integer raddrift;                       // aktueller Zustand
list    particle_parameters;

//==== E N D   G L O B A L   V A R I A B L E   D E C L A R A T I O N ====

// Ermitteln der aktuellen Linknummer anhand des Linknamens
integer getlink(string linkname)
{
    integer linknummer = llGetNumberOfPrims();
    do
    {   
        if (linkname == llGetLinkName(linknummer)) { return (linknummer);}
        linknummer--;
    }
    while (linknummer > 0);
    return (0);
}


integer berechtigungscheck(string clicker)  // Funktion um Zugangsberechtigung auszuwerten
{
    integer zugang = FALSE;
    if (clicker == "") { llSay(0,"ungültige USER UUID übergeben"); return zugang;}
    if (publicaccess) { zugang = TRUE; if(debug)llSay(0,"Publiczugang erteilt"); return zugang;}                                 // Öffentlicher Zugang
    if (groupaccess) { if(llSameGroup( clicker)) { zugang = TRUE;  if(debug)llSay(0,"Gruppenzugang erteilt"); return zugang;} }  // Gruppenzugang
    if (clicker == llGetOwner()) { zugang = TRUE;   if(debug)llSay(0,"Ownerzugang erteilt"); return zugang;}                     // Besitzer Zugang immer erlaubt
    integer uuidzugang = llGetListLength(zugangsliste);  // Anzahl der persönlich berechtigten AVAs ermitteln
    if (uuidzugang)                                      // Persönlicher Zugang über UUID Liste
    {
        string personal;
        do
        {
            personal = llList2String(zugangsliste, uuidzugang -1 );
            if( clicker ==  personal) { zugang = TRUE;  if(debug)llSay(0,"UUIDzugang erteilt"); return zugang;}
            uuidzugang--;
        }
        while (uuidzugang);
    }
    return zugang;
}


rauchpartikel()                                     // Rauchpartikel Vorab initialisieren um in der Fahrschleife Zeit zu sparen
{
    particle_parameters =
        [         
           PSYS_SRC_TEXTURE, llGetInventoryName(INVENTORY_TEXTURE, 0),  // erste Textur aus Prim auslesen und nehmen
           PSYS_PART_START_SCALE,  <3.0000,3.00000,3.00000>,
           PSYS_PART_END_SCALE, <7.5,7.5,7.5>,
           PSYS_PART_START_COLOR, <0.2 , 0.2 ,0.2 >,
           PSYS_PART_END_COLOR, <0.4,0.4,0.4>,
           PSYS_PART_START_ALPHA, 0.75,
           PSYS_PART_END_ALPHA, 0.0,
           PSYS_SRC_BURST_PART_COUNT, rauchpartikelzahl,
           PSYS_SRC_BURST_RATE, 0.1, //0.3
           PSYS_PART_MAX_AGE, 2.0,
           PSYS_SRC_MAX_AGE,(float) 0.0,
           PSYS_SRC_PATTERN, 2,
           PSYS_SRC_BURST_SPEED_MIN, 1.0,
           PSYS_SRC_BURST_SPEED_MAX, 2.05,
           PSYS_SRC_BURST_RADIUS, 0.1,
           PSYS_SRC_ANGLE_BEGIN, (float) 0.08*PI,
           PSYS_SRC_ANGLE_END, (float) 0.08*PI,
           PSYS_SRC_ACCEL, <2,0,-.3>,
           PSYS_PART_FLAGS, (integer)( 0 | PSYS_PART_INTERP_COLOR_MASK | PSYS_PART_INTERP_SCALE_MASK | PSYS_PART_EMISSIVE_MASK )
         ];
}


hinterraddrift(integer raddriftenlassen)            // Durchdrehendes Hinterrad: Rauch Erzeugung und Fahrwerte ändern: an / aus
{
    raddrift = raddriftenlassen;
    if (raddrift)
    {
        llMessageLinked(LINK_SET, 10, "2", NULL_KEY);
        llLinkParticleSystem(hinterradlink, particle_parameters );
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY,0.1);   // SPURTREUE: starkes seitliches Driften des Hinterrades 0.2
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 40.00); // DRIFTZEIT: starkes Nachdriften des durchdrehenden Hinterrades 10.0
        lenkradius = 8;
    }
    else
    {
        llMessageLinked(LINK_SET, 10, "1", NULL_KEY);
        llLinkParticleSystem(hinterradlink, []);
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY,1.0);  // SPURTREUE: kein seitliches Driften des Hinterrades 1.0
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 1.0);  // DRIFTZEIT: wenig Nachdriften des Hinterrades 1.0
        lenkradius = 4;
    }
}


bikeausrichten(integer park)              // Richtet das Bike in Park und Fahr Positionen aus
{
    rotation bikerot =  llGetRot();
    if (park) llSetRot(<-0.4, bikerot.y, bikerot.z, PI>);    // Bike parken (<0.0, -0.20, bikerot.z, PI>);
    else llSetRot(<0.0, bikerot.y, bikerot.z, PI>);           // Bike fahren  
}


frontlicht(integer an)                     // Schaltet Frontlicht an oder aus
{
    // PRIM_POINT_LIGHT, TRUE, primcolor, fIntensity, fRadius, fFalloff ]
    if (an)
    {  
        llSetLinkPrimitiveParamsFast(frontlichtlink, [PRIM_GLOW, frontlichtface, 1.0]);
        llSetLinkPrimitiveParamsFast(lichtkegellink, [PRIM_POINT_LIGHT, TRUE, <1.0, 1.0, 1.0>, 1.0, 10.0, 0.20, PRIM_GLOW, ALL_SIDES, 0.05]);
        llSetLinkPrimitiveParamsFast(bremslichtlink, [PRIM_POINT_LIGHT, FALSE, <1.0, 0.0, 0.0>, 0.0, 0.0, 0.0, PRIM_GLOW, bremslichtface, 0.5]);
    }
    else
    {
        llSetLinkPrimitiveParamsFast(frontlichtlink, [PRIM_GLOW, frontlichtface, 0.0]);
        llSetLinkPrimitiveParamsFast(lichtkegellink, [PRIM_POINT_LIGHT, FALSE, <0.0, 0.0, 0.0>, 0.0, 0.0, 0.0, PRIM_GLOW, ALL_SIDES, 0.0]);
        llSetLinkPrimitiveParamsFast(bremslichtlink, [PRIM_POINT_LIGHT, FALSE, <1.0, 0.0, 0.0>, 0.0, 0.0, 0.0, PRIM_GLOW, bremslichtface, 0.0]);
    }
}


bremslicht(integer bremse)                // Schaltet Bremslicht an oder aus
{
    if (bremse) {llSetLinkPrimitiveParamsFast(bremslichtlink, [PRIM_POINT_LIGHT, TRUE, <1.0, 0.0, 0.0>, 1.0, 2.0, 0.5 , PRIM_GLOW, bremslichtface, 1.0]);}
    else {llSetLinkPrimitiveParamsFast(bremslichtlink, [PRIM_POINT_LIGHT, FALSE, <1.0, 0.0, 0.0>, 0.0, 0.0, 0.0, PRIM_GLOW, bremslichtface, 0.5]);}
    bremslicht_ist_an = bremse;
}


integer tankanzeige(integer funktion )
{
    if (funktion == 1)
    {
        string kmh = (string)llRound(fahrtgeschwindigkeit * 5);
    float drehzahl = llList2Float(getriebeliste, gang );
    if (drehzahl == 0)  drehzahl = 0.001;
        string rpm = (string)llRound(((fahrtgeschwindigkeit / drehzahl)*7000)+600);
        if(gang < 2) rpm = "600";
        string liter = (string) llRound((benzintank / 50));
       
        if (benzintank < ( vollertank * 0.15))
            {
                if(benzintank > 0) { llSetText( kmh + " kmh \n Gang: "+ gangname + " rpm: "+ rpm +  "  \n Benzin: RESERVE " + liter +" Liter",<1,0,0>,1.0); return(TRUE);}
                else { benzintank = 0;  antriebskraft = 0; llSetText( kmh + " kmh \n Gang: "+ gangname + " rpm: 0  \n Benzin: TANK LEER " ,<1,0,0>,1.0); return(FALSE);}
            }
        else { llSetText( kmh + " kmh \n Gang: "+ gangname + " rpm: "+ rpm +  "  \n Benzin: " + liter +" Liter",<1,1,1>,1.0); return(TRUE);}
    }
    else {llSetText("",<0,0,0>,0.0); return(TRUE);}
}


init_engine()                            // Vorinitialisierung des Bikes
{
    bikefahrt = FALSE;
    ganganzahl = llGetListLength(getriebeliste);
    llSetSitText("Biker");
    llSitTarget(sitzposition, ZERO_ROTATION);
    llSetLinkPrimitiveParamsFast(LINK_ALL_CHILDREN, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_NONE]);
    // LINKNummern ermitteln anhand Namen der Links
    bremslichtlink = getlink("Bremslicht");
    frontlichtlink = getlink("Scheinwerfer");
    lichtkegellink = getlink("Lichtkegel");   // Lichtkegelprims vor Fahrzeug
    hinterradlink  = getlink("Hinterrad");
}


gangschaltung(string schalte)            // Gangumschaltung
{   
    string neueanimation;

    if (schalte == "Leerlauf") { gang = 1; llMessageLinked(LINK_SET, 10, "0", NULL_KEY); llMessageLinked(LINK_SET, 20, (string)0, NULL_KEY);} // in Leerlauf schalten
    else if (schalte == "Rückwärts") { gang = 0; llSleep(0.5); init_fahrercam(-45.0, 6.0); llMessageLinked(LINK_SET, 10, "-1", NULL_KEY); } // Rückwärts Gang einlegen
    else if (schalte == "Vorwärts") { gang = 2;  llSleep(0.5); init_fahrercam(0.0, 2.5); llMessageLinked(LINK_SET, 10, "1", NULL_KEY);}  // in 1. Gang schalten
    else if (schalte == "+") { gang += 1;}  // in höheren Gang schalten
    else { gang -= 1;}    // schalte in niedrigeren Gang

    antriebskraft = llList2Float(getriebeliste, gang);
    float drehmoment = llList2Float(beschleunigungsListe, gang);
    llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, drehmoment);
   
    neueanimation = llList2String(ganganimationListe, gang);
    gangname =  llList2String(gangListe , gang);
    benzin = tankanzeige(1);
   
    hinterraddrift(FALSE);
    if (neueanimation != animation) // Animationswechsel
        {
            llStopAnimation(animation);
            animation = neueanimation;
            llStartAnimation(animation);
        }
    if (gang == 1){ llSetTimerEvent(0.0);} else llSetTimerEvent(1.0);
}


// *** KAMERA EINSTELLEN
init_fahrercam(float angle, float distance)
{
    llSetCameraParams(
        [
            CAMERA_ACTIVE, 1,                 // 0=INACTIVE  1=ACTIVE
                CAMERA_BEHINDNESS_ANGLE, angle,   // (0 to 180) DEGREES
                CAMERA_BEHINDNESS_LAG, 1.3,       // (0 to 3) SECONDS  0.3
                CAMERA_DISTANCE, distance,        // ( 0.5 to 10) METERS 2.5
                CAMERA_PITCH, 12.0,               // (-45 to 80) DEGREES
                CAMERA_POSITION_LOCKED, FALSE,    // (TRUE or FALSE)
                CAMERA_POSITION_LAG, 0.25,        // (0 to 3) SECONDS 0.05
                CAMERA_POSITION_THRESHOLD, 0.0,   // (0 to 4) METERS
                CAMERA_FOCUS_LOCKED, FALSE,       // (TRUE or FALSE)
                CAMERA_FOCUS_LAG, 0.0,            // (0 to 3) SECONDS
                CAMERA_FOCUS_THRESHOLD, 0.0,      // (0 to 4) METERS
                CAMERA_FOCUS_OFFSET, <0, 0, 0>    //  METERS
        ]);
    llForceMouselook(FALSE);
}


set_engine()
{
    llSetVehicleType(VEHICLE_TYPE_CAR);
   
     // default rotation of prim
        llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME, <0.00, 0.00, 0.00, 1.00>);
       
// VEHICLE FLAGS
    // llSetVehicleFlags(  VEHICLE_FLAG_NO_DEFLECTION_UP |
    //        VEHICLE_FLAG_LIMIT_ROLL_ONLY |
    //        VEHICLE_FLAG_LIMIT_MOTOR_UP);
        llSetVehicleFlags( VEHICLE_FLAG_NO_DEFLECTION_UP | VEHICLE_FLAG_HOVER_TERRAIN_ONLY);    // Fahrzeug Grundausrichtung bei falschen Mesh Axen
       

// LINEAR MOTOR ANTRIEB UND SPURTREUE
        llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 1.0);                // 1.0 BESCHLEUNIGUNG des MOTORS: Wirkung: Größere Zahl ergibt geringere Beschleunigung. 10 Gut für hohen Gang
        llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, motorbremse);  // 2.0 MOTORBREMSE: Wirkung: Kleinere Zahl größere Motorbremswirkung
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY,1.0);           // 1.0 SPURTREUE: bewirkt starkes seitliches driften des Hinterrades. 0.2 driftet stark für Start mit drehenden rauchenden Reifen, 0.5 leichtes driften. 1 fährt Spurtreu
        llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 1.00);           // 1.0 DRIFTZEIT nach Lenkstop: Kleine Zahl kurzes Nachdriften [1, .. , 100 ] Griffigkeit der Strasse simulierbar. 1trockener Asphalt, 100 Eis. 10 für Start mit drehenden rauchenden Reifen,

// ANGULAR MOTOR LENKUNG UND NEIGUNG BEI KURVEN
        llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, lenkansprechverhalten);     // REAKTIONSZEIT der LENKUNG
        llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, lenkberuhgungszeit);  // NACHLENKZEIT bis GERADEAUSLAUF
        llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 1.00);                // 1.0 SPURTREUE  wird dynamisch eingestellt
        llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 1.00);  // 1.00 DRIFTZEIT

// Friction Reibung
        llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE,  <1.0,1.0,1.0>  );  // ohne sichtbare Auswirkung <1.0,1.0,0.10>
        llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <1.0,1.0,1.0> );  // ohne sichtbare Auswirkung  <1.0,1.0,1.0>

// Vertical Attraction Vertikale Zugkraft
        llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 1.0);  // ohne sichtbare Auswirkung 5.5
        llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1.00);  // 1.0  FINAL sonst säuft Nase in Kurven ab // Werte <= 0.4 ZAPPELT Fahrzeug schlecht! SOLL1

// BANKING Nachschieben
        llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, 1.0 );
        llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, 0.5 );
        llSetVehicleFloatParam( VEHICLE_BANKING_MIX, 1.0 );
        llCollisionSound("", 0.0);
}


default
{
    state_entry()
    {
        if(!debug) llSetLinkTexture(LINK_THIS,llGetInventoryName(INVENTORY_TEXTURE, 0), ALL_SIDES);  // Partikeltextur auf roortprim vorladen damit sie sofort angezeigt wird
        bikeausrichten(TRUE);
        init_engine();
        rauchpartikel();
        llSetText("",<0,0,0>,0.0);
        state Fahrbereit;
    }
   
    on_rez(integer param) { llResetScript();}
}


state Fahrbereit
{
    state_entry() {}


    on_rez(integer param) { llResetScript();}


    changed(integer change)
    {
        if ((change & CHANGED_LINK) == CHANGED_LINK)
        {
            biker = llAvatarOnSitTarget();    // wir haben einen Fahrer
            if (biker != NULL_KEY)
                {
                    access = berechtigungscheck(biker);        // Funktion für Berechtigungs Check aufrufen
                    if(access) {llRequestPermissions(biker, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA | PERMISSION_TRACK_CAMERA);}
                    else
                    {
                        llInstantMessage(biker, "Sorry du hast keine Erlaubnis dieses Fahrzeug zu nutzen");
                        llPushObject(biker, <3,3,21>, ZERO_VECTOR, FALSE);
                    }
                }
            else
            {   // Fahrer ist aufgestanden
                llMessageLinked(LINK_SET, 10, "0", NULL_KEY);  // Räder stoppen
                llSetTimerEvent(0.0);
                llSetStatus(STATUS_PHYSICS, FALSE);
                bikeausrichten(TRUE);
                bremslicht(FALSE);                 // Bremslicht ausschalten
                frontlicht(FALSE);
                bikefahrt = FALSE;
                llStopAnimation(animation);
                hinterraddrift(FALSE);
                llPushObject(biker, <3,3,21>, ZERO_VECTOR, FALSE);
                llReleaseControls();
                llClearCameraParams();
                llSetCameraParams([CAMERA_ACTIVE, 0]);
                benzin = tankanzeige(FALSE);
               // llResetScript(); // Hinderlich bei Benzinberechnung. Ansonsten gut
                llListenRemove(listenhandle);
                state default;
            }
        }
    }

    run_time_permissions(integer perm)
    {
        if (perm)
        {
            set_engine();                // MOTOR einstellen
            listenhandle = llListen(channel,"","","");
            bikeausrichten(FALSE);
            llSetStatus(STATUS_PHYSICS | STATUS_ROTATE_X | STATUS_ROTATE_Y | STATUS_ROTATE_Z, TRUE);
            frontlicht(TRUE);
            bikefahrt = TRUE; // BIKE fährt
            animation = "sit";
            gangschaltung("Leerlauf"); // im Leerlauf starten und Animation ändern
            benzin = tankanzeige(TRUE);
            init_fahrercam(0.0, 2.5);
            llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_DOWN | CONTROL_UP | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT, TRUE, FALSE);
            llSleep(1.5);
        }
    }


    control(key id, integer tastenzustand, integer tastenaenderung)
    {
        if(!bikefahrt){return;}
        vector AngularMotor;
       
        integer tastefrischgedrueckt = tastenzustand & tastenaenderung;   
        integer tastelosgelassen = ~tastenzustand & tastenaenderung;
     //     integer tastegehalten = tastenzustand & ~tastenaenderung;
     //     integer tastenichtgehalten = ~tastenzustand & ~tastenaenderung;

        vel = llGetVel();
        fahrtgeschwindigkeit = llVecMag(vel);            // Geschwindigkeit
        fahrfaktor = fahrtgeschwindigkeit /10;     // Hilfsvariable zur Rechenreduktion


// in höheren Gang schalten mit BILD AUF
        if(tastefrischgedrueckt & (CONTROL_UP | CONTROL_RIGHT)) { if (gang < (ganganzahl -1)) gangschaltung("+");}
// sonst in niedrigerne Gang schalten mit BILD AB
        else if(tastefrischgedrueckt & (CONTROL_DOWN | CONTROL_LEFT)) { if (gang > 0) gangschaltung("-");}


// weiterhin Vorwärts Gas geben
        if (tastenzustand & CONTROL_FWD)
        {
            if (gang < 2) gangschaltung("Vorwärts");        // Auf 1. Gang schalten wenn kein Vorwärtsgang eingelegt war
            else { llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft,0,0>);} // Linear Motor Kraft geben
           
// Sport Gangschaltung aufwärts
  //          if  ((tastefrischgedrueckt & CONTROL_ROT_RIGHT) && (tastefrischgedrueckt & CONTROL_ROT_LEFT))  { if (gang < (ganganzahl -1)) gangschaltung("+"); tastefrischgedrueckt = FALSE; tastenzustand = FALSE; llSleep(0.1); return; }
// Sport Gangschaltung abwärts
            if ((tastefrischgedrueckt & CONTROL_BACK)) {if (gang > 2) gangschaltung("-"); tastefrischgedrueckt = FALSE; tastenzustand = FALSE; llSleep(0.1); return; }
      
        }
// sonst Rückwärts schalten (nur wenn kein Gas gegeben wird, und Fahrzeug fast im Stillstand)
        else if (tastefrischgedrueckt & CONTROL_BACK) { if ((fahrtgeschwindigkeit < 0.5 ) && (gang > 0)) { gangschaltung("Rückwärts");}}

// weiterhin Rückwärts fahren oder Bremsen
        if (tastenzustand & CONTROL_BACK)
        {
            if (gang > 1)
            {
                if (!bremslicht_ist_an) bremslicht(TRUE);
                if(fahrtgeschwindigkeit > 9) {llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <-bremskraft, 0, 0>);} // stark Bremsen
                else llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0, 0, 0>);  // sanft Bremsen, Rückwärts fahren verhindern
            }
            else if (gang == 0) { llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft, 0, 0>);} // Rückwärts fahren
        }
// sonst Bremse lösen
        else if (tastelosgelassen & CONTROL_BACK){ if (bremslicht_ist_an) bremslicht(FALSE); llMessageLinked(LINK_SET, 20, (string)fahrtgeschwindigkeit, NULL_KEY);}


// Vorderrad Aufsteigen bei Vorwärtsfahrt und links + rechts Pfeiltasten
        if  ((tastenzustand & CONTROL_ROT_RIGHT) && (tastenzustand & CONTROL_ROT_LEFT))
        {
            if((gang == 2) || (gang == 3))        // nur im 1. und 2. Gang aufsteigen lassen
            {
                rechtslenk++; linkslenk++; // eventuell rauchende Reifen erhalten
                AngularMotor.y -= ( 2.7 ); // Vorderrad aufsteigen lassen
                if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <5.0, 0, 0>); // Vortrieb falls zu langsam für Aufsteigen           
            }
        }
       
// RECHTS lenken
        if  (tastenzustand & CONTROL_ROT_RIGHT)
        {
           if( gang > 1)   // Einknicken in Kurvenmittelpunkt bei Vorwärtsfahrt
            {
                rechtslenk++;
             //   AngularMotor.y -= ( 1.15 ); // Nase hoch zur Kompensation des Eintauchens 0.75
                if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <3.0, 0, 0>); // Vortrieb falls zu langsam für Kurvenfahrt
                if ((rechtslenk > 30) & (gang == 2) & (fahrtgeschwindigkeit > 4.5)) { if (!raddrift) hinterraddrift(TRUE);}     // Hinterrad rotieren lassen
            }
            AngularMotor.y -= ( 1.15 ); // Nase hoch zur Kompensation des Eintauchens 0.75
            AngularMotor.x += ( einknicken + fahrfaktor );       // Seitlich einknicken steigt mit Geschwindigkeit (3-6 gut)
            if(gang >0) AngularMotor.z -= ( lenkradius - fahrfaktor );    // Lenkung wird mit steigender Geschwindigkeit wirkungsloser
            else if(!gang) AngularMotor.z += 4;                            // Rueckwärts invers lenken
        }
// Nicht mehr rechts lenken
        else if (tastelosgelassen & CONTROL_ROT_RIGHT){ rechtslenk = 0; llMessageLinked(LINK_SET, 30, (string)0, NULL_KEY);}

// LINKS Lenken
        if (tastenzustand & CONTROL_ROT_LEFT)
        {
           if( gang > 1)  // Einknicken in Kurvenmittelpunkt bei Vorwärtsfahrt
            {
                linkslenk++;
            //    AngularMotor.y -= ( 1.15 ); // Nase hoch zur Kompensation des Eintauchens
                if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <3.0, 0, 0>); // Vortrieb falls zu langsam für Kurvenfahrt
                if ((linkslenk > 30) & (gang == 2) & (fahrtgeschwindigkeit > 4.5)) { if (!raddrift) hinterraddrift(TRUE);}      // Hinterrad rotieren lassen
            }
            AngularMotor.y -= ( 1.15 ); // Nase hoch zur Kompensation des Eintauchens
            AngularMotor.x -= ( einknicken + fahrfaktor );       // Seitlich einknicken steigt mit Geschwindigkeit (3-6 gut)           
            if(gang >0) AngularMotor.z += ( lenkradius - fahrfaktor );    // Lenkung wird mit steigender Geschwindigkeit wirkungsloser
            else if(!gang) AngularMotor.z -= 4;                            // Rueckwärts invers lenken
        }
// Nicht mehr links lenken
        else if (tastelosgelassen & CONTROL_ROT_LEFT){ linkslenk = 0;}

        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, AngularMotor);     // ROTATIONS MOTOR mit Kraft versorgen
        if ((!rechtslenk) & (!linkslenk) & raddrift) {hinterraddrift(FALSE);}        // rauchende Reifen abschalten
    }
   
   
    timer()
    {
        vel = llGetVel();
        fahrtgeschwindigkeit = llVecMag(vel);      // beide Richtugnen haben positive Geschwindigkeit!
        float verbrauch = fahrtgeschwindigkeit / 20;    // Hilfsvariable zur Rechenreduktion
        if(racemode)
        {   
            benzintank -= verbrauch;                  // Spritverbrauch
            benzin = tankanzeige(1);
        }
        if((gang != 1) & (fahrtgeschwindigkeit < 0.1)) { gangschaltung("Leerlauf"); fahrtgeschwindigkeit = 0.0;} // bei Stand in Leerlauf schalten
        llMessageLinked(LINK_SET, 20, (string)fahrtgeschwindigkeit, NULL_KEY);
    }


    listen(integer channel, string name, key id, string message)
    {
        string sender =  llGetSubString( message, 0, 35 );

        if(biker == sender)
        {
            float tankmenge =  ((vollertank - benzintank)/50);
            string befehl =  llGetSubString( message, 36, llStringLength( message ));
            if(befehl == "Tanken")
            {
                if(gang ==1)
                {
                    llWhisper(0, (string)tankmenge + "Liter Super getankt, das macht dann €:" + (string)(tankmenge *1.57));
                    benzintank = vollertank;
                    if(racemode) benzin = tankanzeige(1);
                }
                else {llWhisper(0, "Bitte zum Tanken den Motor abstellen");}
            }
        }
    }
}
Zitieren
#8
Update auf Version 3.0.1 am 24.08.2022

Ich habe die Funktion Tankanzeige geändert weil es (nur) unter der Opensim Version 0.9.2.1 unter Umständen zu einem Scritpfehler "Division durch Zero" kam. Dieser Fehler entstand wenn man in den Parametern der Getriebeliste eine 0 einfügte. Das Update ist im letzten 3.x Post erfolgt.

Tron
Zitieren


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste