PKW SCRIPT für BULLET in OPENSIM
Version 3.01 Stand 24.08.2022.
Nachdem die Neuentwicklung meines Motorrad Script gut angekommen ist, ergänze ich dies um eine Anpassung für PKWs.
Es ist vom Stil an das Motorrad Script angelehnt, jedoch in der Fahrdynamik eigenständig um einen maximalen Fahrspaß bei simpler Bedienung zu ermöglichen.
Das Script ist explizit für langsame Stadtfahrzeuge optimiert, um ein präzises Fahren selbst auf kleinen Strassen zu ermöglichen.
Diesmal auf Moes Wunsch mit integrierten Fahrer Berechtigungs Check, damit Stella Herzchen auch mal fahren darf.
Schliesslich ist dieses Scritp perfekt damit Stella mit ihrem Stadtautochen zum Einkaufen fährt, und die Kinder zur Schule bringt.
Ich hätte diesmal ja sogar fast ein Autoradio eingebaut damit die Kinder auf dem Wege zur Schule "Käpten Blaubär" hören können, habs mir aber verkniffen.
Es ermöglicht Fahrberechtigungen nach folgenden Usergruppen zu setzten:
- Der Inhaber des Fahrzeugscheins (Besitzer) darf immer
- Die Ehefrau kann per UUID explizit im Script aufgeführt werden. Ebenso der 18jährige Bengel der Mamas Auto benutzen darf.
- Karrensharing innerhalb der gleichen Gruppe wird auch unterstützt.
- Und wenn ihr den Zündschlüssel stecken klassen wollt, dann kann jeder das Fahrzeug nutzen.
Wie immer gilt:
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.
Wer schon das Bike script kennt braucht nun nicht weiterzulesen, und kann es direkt einsetzten.
Für alle Einsteiger aber noch mal eine angepasste Zusammenfassung was das Script bietet, und wie es einzusetzen ist:
FAHREN:
- das Auto 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 Auto 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, Radhaftung
- Es gibt einen Leerlauf in dem das Auto nicht physisch ist. Auch wird in diesem Modus getankt.
FAHRERANIMATIONEN:
- Es wird pro Gang eine eigene Fahrer Animation unterstützt.
BENZINVERBRAUCH:
- Das Auto 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 Auto hat sich als "vollertank" 4000 bewährt was 80L entspricht.
Die initiale Tankfüllung nach Scriptreset wird in "benzintank" festgelegt. Das habe ich auf 2000 eingestellt was 40L entspricht.
LICHT:
- es gibt Unterstützung für 2 Bremslichter/Rücklichter.
- es gibt Unterstützung für 2 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)
"Bremslicht1", "Bremslicht2", "Scheinwerfer1", "Scheinwerfer2", "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".
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>
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. (Stand 8.2022 Auto und Bike)
Wenn jemand seine Fahrzeugscripte in das Tanksystem integrieren will, bitte hier posten für Hilfe, oder aus dem Auto Script herauslesen
Wie immer wünsche ich viel Spaß, und freue mich auf konstruktive Rückmeldungen.
Das Radscript könnte noch Verbesserungen vertragen, insbesondere Lenken, jedoch ist dafür Mesh mit entsprechden Achsen notwendig.
Es ist halt auch immer ein Zeitfaktor der die Arbeit für Opensim begrenzt. Ich hab jedenfalls für Heute keine Lust mehr am kleinen 13" Laptop in FullHD Buchstaben zu erahnen, und werde mich an den Strand begeben.
Tron
Version 3.01 Stand 24.08.2022.
Nachdem die Neuentwicklung meines Motorrad Script gut angekommen ist, ergänze ich dies um eine Anpassung für PKWs.
Es ist vom Stil an das Motorrad Script angelehnt, jedoch in der Fahrdynamik eigenständig um einen maximalen Fahrspaß bei simpler Bedienung zu ermöglichen.
Das Script ist explizit für langsame Stadtfahrzeuge optimiert, um ein präzises Fahren selbst auf kleinen Strassen zu ermöglichen.
Diesmal auf Moes Wunsch mit integrierten Fahrer Berechtigungs Check, damit Stella Herzchen auch mal fahren darf.
Schliesslich ist dieses Scritp perfekt damit Stella mit ihrem Stadtautochen zum Einkaufen fährt, und die Kinder zur Schule bringt.
Ich hätte diesmal ja sogar fast ein Autoradio eingebaut damit die Kinder auf dem Wege zur Schule "Käpten Blaubär" hören können, habs mir aber verkniffen.
Es ermöglicht Fahrberechtigungen nach folgenden Usergruppen zu setzten:
- Der Inhaber des Fahrzeugscheins (Besitzer) darf immer
- Die Ehefrau kann per UUID explizit im Script aufgeführt werden. Ebenso der 18jährige Bengel der Mamas Auto benutzen darf.
- Karrensharing innerhalb der gleichen Gruppe wird auch unterstützt.
- Und wenn ihr den Zündschlüssel stecken klassen wollt, dann kann jeder das Fahrzeug nutzen.
Wie immer gilt:
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.
Wer schon das Bike script kennt braucht nun nicht weiterzulesen, und kann es direkt einsetzten.
Für alle Einsteiger aber noch mal eine angepasste Zusammenfassung was das Script bietet, und wie es einzusetzen ist:
FAHREN:
- das Auto 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 Auto 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, Radhaftung
- Es gibt einen Leerlauf in dem das Auto nicht physisch ist. Auch wird in diesem Modus getankt.
FAHRERANIMATIONEN:
- Es wird pro Gang eine eigene Fahrer Animation unterstützt.
BENZINVERBRAUCH:
- Das Auto 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 Auto hat sich als "vollertank" 4000 bewährt was 80L entspricht.
Die initiale Tankfüllung nach Scriptreset wird in "benzintank" festgelegt. Das habe ich auf 2000 eingestellt was 40L entspricht.
LICHT:
- es gibt Unterstützung für 2 Bremslichter/Rücklichter.
- es gibt Unterstützung für 2 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)
"Bremslicht1", "Bremslicht2", "Scheinwerfer1", "Scheinwerfer2", "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:
// P319 PKW Script für Simcrossing in Opensim 09 by Tron
// Stand 24.08.2022 V3.01
// unterstützt Hinterraddrift im Sportwagen Modus,
// verbaucht Benzin und zeigt Fahrwerte an im Racemodus
// Gangschaltung mit Leerlauf
// Partikel Textur auf PRIM1 (Fahrzeugprim) vorladen damit diese sofort angezeigt wird
// V3.0.1: Änderung der Funktion Tankanzeige da es (nur) in Opensim 0.9.2.1 einen Division durch 0 Fehler gab wenn Getriebeliste als Parameter eine 0 enthält.
// 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 = 2.0; // Motorbremswirkung 1.0 gut, 2.0 weniger Bremswirkung für längerere Auslauf
list getriebeliste = [ -5 , 0.001, 15, 25, 35, 50, 70 ]; // Maximalkraft & Geschwindigkeit des Motors je Gang [ -5 , 0, 15, 25, 35, 55, 70 ];
list beschleunigungsListe = [1.0, 100.0 , 2.0, 4.0, 8.0, 14.0, 20.0]; // Beschleunigungsdauer des Motors bis maximaler Ganggeschwindigkeit. 1 = schnell [1.0, 100.0 , 1.0, 3.0, 6.0, 10.0, 15.0];
list lenkradiusliste = [ 4, 4, 4, 4, 4, 4, 3 ]; // Wenderadius. Größere Werte ermöglichen kleinerer Wendekreise. Gut 4-5 [ 4, 4, 4, 4, 5, 5, 5 ];
list ganganimationListe = ["drive","drive","drive","drive","drive","drive","drive"]; // unterschiedliche Animationen je Gang
list gangListe = ["Rückwärts","Leerlauf","1. Gang","2. Gang","3. Gang","4. Gang","5. Gang"]; // Bezeichnung der Gänge
// LENKUNG
float lenkansprechverhalten = 0.4; // 0.32 REAKTIONSZEIT der LENKUNG 0.2 knackig, 0.3 medium, 0,4träge
float lenkberuhgungszeit = 0.5; // 0.80 NACHWIRKZEIT der LENKUNG 0.2++ sehr direkt // 0.5 gut // 1.2 träge
float lenkradius;
integer racemode = TRUE; // Zeigt Geschwindigkeit und Benzin an, und verbraucht Benzin
integer sportwagen = FALSE; // Erlaubt Hinterrad Drift und anderes Fahrverhalten. Nicht für Stadtautos
vector sitzposition = <1.05,0.45,1.05>;// Sitzposition <0.65,0.25,0.95>
// Linknummern des FAHRZEUGS werden automatisch ermittelt anhand LINKNAMEN. Faces manuell eingetragen
integer bremslichtlink; // Bremslicht 1
integer bremslichtlink2; // Bremslicht 2
integer bremslichtface = 1; // Face des Bremslichtes
integer frontlichtlink; // Frontscheinwerfers 1
integer frontlichtlink2; // Frontscheinwerfers 2
integer frontlichtface = 2; // Face des Frontscheinwerfer manuell eintragen
integer lichtkegellink; // Lichtkegelprims vor dem Bike
integer hinterradlink; // Hinterrades für Rauch
integer lenkradlink; // Lenkrad
// TANKDIMENSIONIERUNG
float vollertank = 4000; // Voller Tank
float benzintank = 2000; // 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 = llList2Float(lenkradiusliste, gang);
}
}
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(frontlichtlink2, [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]);
llSetLinkPrimitiveParamsFast(bremslichtlink2, [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(frontlichtlink2, [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]);
llSetLinkPrimitiveParamsFast(bremslichtlink2, [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]);
llSetLinkPrimitiveParamsFast(bremslichtlink2, [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]);
llSetLinkPrimitiveParamsFast(bremslichtlink2, [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 * 6);
float drehzahl = llList2Float(getriebeliste, gang );
if (drehzahl == 0) drehzahl = 0.001;
string rpm = (string)llRound(((fahrtgeschwindigkeit / drehzahl)*7000)+700);
if(gang < 2) rpm = "700";
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("Fahrer");
llSitTarget(sitzposition, ZERO_ROTATION);
llSetLinkPrimitiveParamsFast(LINK_ALL_CHILDREN, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_NONE]);
// LINKNummern ermitteln anhand Namen der Links
bremslichtlink = getlink("Bremslicht1");
bremslichtlink2 = getlink("Bremslicht2");
frontlichtlink = getlink("Scheinwerfer1");
frontlichtlink2 = getlink("Scheinwerfer2");
lichtkegellink = getlink("Lichtkegel"); // Lichtkegelprims vor Fahrzeug
hinterradlink = getlink("Hinterrad");
lenkradlink = getlink("Lenkrad");
}
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
lenkradius = llList2Float(lenkradiusliste, gang);
antriebskraft = llList2Float(getriebeliste, gang);
float drehmoment = llList2Float(beschleunigungsListe, gang);
llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, drehmoment);
neueanimation = llList2String(ganganimationListe, gang);
gangname = llList2String(gangListe , gang);
if(racemode) {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_HOVER_UP_ONLY | VEHICLE_FLAG_LIMIT_MOTOR_UP);
// 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
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
llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <1.0,1.0,1.0> ); // ohne sichtbare Auswirkung
// Vertical Attraction Vertikale Zugkraft
llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 1.0); // 1.0 wichtig
llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 5.00);
// BANKING Nachschieben vermutlich ohne Wirkung
llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.0 );
llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 0.0 );
llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, 0.0 );
llSetVehicleFloatParam(VEHICLE_BUOYANCY, 0.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
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);
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,"","","");
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
// if(racemode) 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 / 20; // Hilfsvariable zur Rechenreduktion
// in höheren Gang schalten mit BILD AUF
if(tastefrischgedrueckt & (CONTROL_UP | CONTROL_RIGHT)) { if (gang < (ganganzahl -1)) gangschaltung("+"); llSleep(0.15); return;}
// sonst in niedrigerne Gang schalten mit BILD AB
else if(tastefrischgedrueckt & (CONTROL_DOWN | CONTROL_LEFT)) { if (gang > 0) gangschaltung("-"); return; }
// 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
else 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);}
// RECHTS lenken
if (tastenzustand & CONTROL_ROT_RIGHT)
{
if(rechtslenk ==0) llMessageLinked(LINK_SET, 30, (string)1, NULL_KEY);
if( gang > 1)
{
rechtslenk++;
if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <3.0, 0, 0>); // Vortrieb falls zu langsam für Kurvenfahrt
if(sportwagen) {if ((rechtslenk > 30) & (gang == 2) & (fahrtgeschwindigkeit > 4.5)) { if (!raddrift) hinterraddrift(TRUE);}} // Hinterrad rotieren lassen
}
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
else if (tastenzustand & CONTROL_ROT_LEFT)
{
if(linkslenk ==0) llMessageLinked(LINK_SET, 30, (string) (-1), NULL_KEY);
if( gang > 1)
{
linkslenk++;
if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <3.0, 0, 0>); // Vortrieb falls zu langsam für Kurvenfahrt
if(sportwagen) {if ((linkslenk > 30) & (gang == 2) & (fahrtgeschwindigkeit > 4.5)) { if (!raddrift) hinterraddrift(TRUE);}} // Hinterrad rotieren lassen
}
if(gang >0) AngularMotor.z += ( lenkradius - fahrfaktor ); // Lenkung wird mit steigender Geschwindigkeit wirkungsloser
else if(!gang) { AngularMotor.z -= 4;} // Rueckwärts invers lenken und Nase kompensieren
}
// Nicht mehr links lenken
else if (tastelosgelassen & CONTROL_ROT_LEFT){ linkslenk = 0; llMessageLinked(LINK_SET, 30, (string)0, NULL_KEY);}
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!
fahrfaktor = fahrtgeschwindigkeit / 20; // Hilfsvariable zur Rechenreduktion
if(racemode)
{
benzintank -= fahrfaktor; // 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. (Stand 8.2022 Auto und Bike)
Wenn jemand seine Fahrzeugscripte in das Tanksystem integrieren will, bitte hier posten für Hilfe, oder aus dem Auto 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);
}
}
}
}
Wie immer wünsche ich viel Spaß, und freue mich auf konstruktive Rückmeldungen.
Das Radscript könnte noch Verbesserungen vertragen, insbesondere Lenken, jedoch ist dafür Mesh mit entsprechden Achsen notwendig.
Es ist halt auch immer ein Zeitfaktor der die Arbeit für Opensim begrenzt. Ich hab jedenfalls für Heute keine Lust mehr am kleinen 13" Laptop in FullHD Buchstaben zu erahnen, und werde mich an den Strand begeben.
Tron