// ============================================================
// OPENSIM WALDPFLANZER SKRIPT MIT DIALOG-MENÜ
// ============================================================
// ===== GLOBALE VARIABLEN =====
integer gIntX;
integer gIntY;
integer gIntZ;
integer gIntStartX;
integer gIntStartY;
integer gIntEndX;
integer gIntEndY;
float gFltPlantProbability;
float gFltRandMax;
// ===== START/STOP-FUNKTION =====
integer gIntRunning = FALSE;
key gKeyToucher;
integer gIntCurrentX;
integer gIntCurrentY;
// ===== PFLANZPARAMETER =====
integer PFLANZABSTAND = 6;
float ROTATION_SCHRITT = 15.0;
float AKTUELLE_ROTATION = 0.0;
// ===== BAUM-KONFIGURATIONEN =====
list BAUM_HOEHEN = [
"European-Beech-tree-A", 10.0,
"European-Beech-tree-B", 10.0,
"European-Oak-tree", 12.0
];
// ===== TERRAIN-TEXTUREN =====
float TextureLow = 10.0;
float TextureHigh = 30.0;
key Terrain_Dirt = "9dc31f61-e30b-44bf-91dc-e4f6a8735407";
key Terrain_Grass = "20a4e1b3-be0f-45ae-9683-54809ac750f7";
key Terrain_Mountain = "ebf2583d-0d94-4066-a684-e39b37fe2f57";
key Terrain_Rock = "429726cd-34e4-4bc9-a669-a94f2f69f11e";
// ===== DIALOG-MENÜ VARIABLEN =====
integer MENU_CHANNEL;
integer listenHandle;
string MENU_TEXT = "\nWähle eine Aktion:";
list MENU_BUTTONS = ["? Pflanzen", "? Terrain", "❌ Schließen"];
// ===== HILFSFUNKTIONEN =====
float getTreeHeight(string treeName)
{
integer index = llListFindList(BAUM_HOEHEN, [treeName]);
if (index != -1)
return llList2Float(BAUM_HOEHEN, index + 1);
return 10.0;
}
rotation getRotation(float grad)
{
return llEuler2Rot(<0.0, 0.0, grad * DEG_TO_RAD>);
}
// ===== TERRAIN-FUNKTIONEN MIT AUFRAUUNG =====
setTerrain()
{
// 1. Texturen setzen (wie gehabt)
list textures = [Terrain_Dirt, Terrain_Grass, Terrain_Mountain, Terrain_Rock];
integer types = 2; // Legacy + PBR
osSetTerrainTextures(textures, types);
// Fallback für ältere Systeme
osSetTerrainTexture(0, Terrain_Dirt);
osSetTerrainTextureHeight(0, TextureLow, TextureHigh);
osSetTerrainTexture(1, Terrain_Grass);
osSetTerrainTextureHeight(1, TextureLow, TextureHigh);
osSetTerrainTexture(2, Terrain_Mountain);
osSetTerrainTextureHeight(2, TextureLow, TextureHigh);
osSetTerrainTexture(3, Terrain_Rock);
osSetTerrainTextureHeight(3, TextureLow, TextureHigh);
// 2. Terrain aufrauen für besseren PBR-Effekt
// ACHTUNG: llModifyLand benötigt Estate-Manager-Rechte!
llModifyLand(LAND_NOISE, 0); // 0, 1, 2 ,3, 4
// 3. Terrain aktualisieren
osTerrainFlush();
llOwnerSay("✅ Terrain-Texturen wurden gesetzt und leicht aufgeraut!");
}
// ===== PFLANZEN-FUNKTIONEN =====
plantOneTree()
{
if (!gIntRunning) return;
if (gIntCurrentX >= gIntEndX || gIntCurrentY >= gIntEndY)
{
gIntRunning = FALSE;
llOwnerSay("✅ Pflanzvorgang abgeschlossen!");
llSetText("Fertig - Klicke für neues Menü", <0,1,0>, 1.0);
llSetTimerEvent(0.0);
return;
}
gIntX = gIntCurrentX;
gIntY = gIntCurrentY;
llSetRegionPos(<gIntX, gIntY, gIntZ>);
llSetText("X: " + (string)gIntX + " Y: " + (string)gIntY + " Rot: " + (string)((integer)AKTUELLE_ROTATION) + "°", <1,1,1>, 1.0);
integer gIntTreePick = (integer) llFrand(gFltRandMax + 1);
float fltDoIRez = llFrand(1.0);
if (fltDoIRez < gFltPlantProbability)
{
string gStrTreeName = llGetInventoryName(INVENTORY_OBJECT, gIntTreePick);
if (gStrTreeName != "")
{
vector vecNowPos = llGetPos();
float fltLandHeight = osGetTerrainHeight((integer)vecNowPos.x, (integer)vecNowPos.y);
integer intNewX = (integer)vecNowPos.x;
integer intNewY = (integer)vecNowPos.y;
integer intNewZ = (integer)fltLandHeight;
vecNowPos = <intNewX, intNewY, intNewZ>;
llSetRegionPos(vecNowPos);
float treeHeight = getTreeHeight(gStrTreeName);
rotation treeRotation = getRotation(AKTUELLE_ROTATION);
llRezObject(gStrTreeName,
llGetPos() + <0.0, 0.0, treeHeight>,
<0.0, 0.0, 0.0>,
treeRotation,
0);
AKTUELLE_ROTATION += ROTATION_SCHRITT;
if (AKTUELLE_ROTATION >= 360.0)
AKTUELLE_ROTATION -= 360.0;
llSleep(0.1);
}
}
gIntCurrentY += PFLANZABSTAND;
if (gIntCurrentY >= gIntEndY)
{
gIntCurrentY = gIntStartY + (PFLANZABSTAND / 2);
gIntCurrentX += PFLANZABSTAND;
}
}
startPlanting()
{
vector regionSize = osGetRegionSize();
gIntStartX = 0;
gIntStartY = 0;
gIntEndX = (integer)regionSize.x;
gIntEndY = (integer)regionSize.y;
gFltPlantProbability = .5;
integer count = llGetInventoryNumber(INVENTORY_OBJECT);
gFltRandMax = (float)count;
gIntZ = 0;
gIntRunning = TRUE;
gIntCurrentX = gIntStartX + (PFLANZABSTAND / 2);
gIntCurrentY = gIntStartY + (PFLANZABSTAND / 2);
AKTUELLE_ROTATION = 0.0;
llOwnerSay("? Starte Pflanzvorgang... Klicke erneut zum Stoppen.");
llSetText("? Pflanze... Klicke zum Stoppen", <1,1,0>, 1.0);
llSetTimerEvent(2.0);
}
// ===== HAUPTTEIL DES SKRIPTS =====
default
{
state_entry()
{
MENU_CHANNEL = -1 - (integer)("0x" + llGetSubString((string)llGetKey(), -7, -1));
llOwnerSay("? Waldpflanzer bereit. Klicke für Menü.");
llSetText("Bereit - Klicke für Menü", <0,1,0>, 1.0);
llSetTimerEvent(0.0);
}
touch_start(integer num_detected)
{
// Wenn gerade gepflanzt wird, soll ein Klick den Vorgang stoppen
if (gIntRunning)
{
gIntRunning = FALSE;
llSetTimerEvent(0.0);
llListenRemove(listenHandle);
llOwnerSay("⏹️ Pflanzvorgang wurde gestoppt!");
llSetText("Gestoppt - Klicke für neues Menü", <1,0,0>, 1.0);
return;
}
// Ansonsten: Dialog-Menü anzeigen
key toucher = llDetectedKey(0);
llListenRemove(listenHandle);
listenHandle = llListen(MENU_CHANNEL, "", toucher, "");
llDialog(toucher, MENU_TEXT, MENU_BUTTONS, MENU_CHANNEL);
llSetTimerEvent(60.0); // Timeout nach 60 Sekunden
}
listen(integer channel, string name, key id, string message)
{
// Timeout zurücksetzen, da eine Auswahl getroffen wurde
llSetTimerEvent(0.0);
llListenRemove(listenHandle);
if (message == "? Pflanzen")
{
llOwnerSay("? Starte Pflanzvorgang...");
startPlanting();
}
else if (message == "? Terrain")
{
setTerrain();
// Optional: Kurze Bestätigung im Dialog
llDialog(id, "✅ Terrain-Texturen wurden aktualisiert.", ["OK"], MENU_CHANNEL);
}
else if (message == "❌ Schließen")
{
llOwnerSay("Menü geschlossen.");
}
else if (message == "OK")
{
// Nur für die Bestätigung nach Terrain-Update
llOwnerSay("✅ OK.");
}
}
timer()
{
// Timeout: Menü und Listener schließen
llSetTimerEvent(0.0);
llListenRemove(listenHandle);
llOwnerSay("⏳ Menü abgelaufen. Klicke erneut für Optionen.");
llSetText("Bereit - Klicke für Menü", <0,1,0>, 1.0);
}
}