User:Daemonika Nightfire/Scripts/Giver Tutorial

From Second Life Wiki
Jump to navigation Jump to search

Simple Giver

Der Landmark Giver ist eines der am haeufigsten verwendeten Scripte in SL, beinahe jeder Shop und Club verfuegt ueber so einen. Da es besonders in Malls in hoher Anzahl vorkommt, sollte man darauf achten so wenig wie moeglich ins Script zu schreiben und nach moeglichkeit den Memory begrenzen, um nicht unnoetig Resourcen zu verschwenden.

/*
    *DS* Simple Landmark Giver by Daemonika Nightfire
    
    Da es sich hier um ein sehr sehr seeeehr kleines Script handelt, habe ich hier das Memory Limit vorgesehen.
    Der Grund liegt ganz einfach darin, den gesamten Region Memory auf diesem Weg so wenig wie moeglich zu belasten.
    
    Genauere Informationen ueber Script-Memory findest du hier:
    https://wiki.secondlife.com/wiki/User:Daemonika_Nightfire/Scripts/Memory_Walkthrough
*/

default
{
    state_entry()
    {
        // manuelles Script Limit (fuer einen simplen Giver voellig ausreichend)
        llSetMemoryLimit(10000);
    }
    
    touch_start(integer total_number)
    {
        // ueberprueft den Inhalt, ob eine Landmarke vorhanden ist und gibt diese aus
        if(llGetInventoryNumber(INVENTORY_LANDMARK) > 0)
        {
            llGiveInventory(llDetectedKey(0),llGetInventoryName(INVENTORY_LANDMARK, 0));
        }
    }
    
    changed(integer change)
    {
        if(change & CHANGED_INVENTORY)
        {
            // resettet das Script, sobald sich der Inhalt des Objects aendert
            llResetScript();
        }
    }
    
    on_rez(integer Dae)
    {
        // resettet das Script, sobald es gerezzt wird
        llResetScript();
    }
}

Natuerlich kann man ein und das selbe Script auch fuer andere Dinge als Landmarken verwenden. Ersetz dazu einfach die Konstanten in den Befehlen llGetInventoryNumber und llGetInventoryName. Die Konstanten beider Befehle sollten natuerlich identisch sein.

Wie man unschwer erkennen kann, steht am ende dieses Befehls eine 0 if(llGetInventoryNumber(INVENTORY_LANDMARK) > 0)
Damit wird geprueft, ob sich im Inhalt des Objects ueberhaupt eine Landmark befindet.

Bei dem zweiten befehl steht ebenfalls eine 0 llGetInventoryName(INVENTORY_LANDMARK, 0)
Hier bedeutet die 0 jedoch, dass die erste Landmark aus dem Inventar ausgegeben wird. Selbst wenn mehrere vorhanden sein sollten.
// Ziemlich nutzlos, dann kann man sich auch das Script sparen.
INVENTORY_NONE

// Als Simple Giver nicht zu empfehlen, wenn man nicht moechte, dass das Script mit ausgegeben wird.
INVENTORY_ALL

// Ideal fuer jeden Shop und Club.
INVENTORY_LANDMARK

// Wird oft im Roleplay verwendet um Regeln zu uebergeben.
INVENTORY_NOTECARD

//
INVENTORY_SOUND

//
INVENTORY_OBJECT

//
INVENTORY_GESTURE

//
INVENTORY_TEXTURE

//
INVENTORY_CLOTHING

//
INVENTORY_BODYPART

//
INVENTORY_SCRIPT

//
INVENTORY_ANIMATION

Advanced Giver

Wenn man nun den Kompletten Inhalt, mit Ausnahme des Scriptes ausgeben moechte, empfiehlt es sich folgendes Script zu verwenden. Ein weiterer Vorteil dieses Scripts ist, es vergibt den Inhalt in einem Ordner. llGiveInventoryList( key target, string folder, list inventory );

/*
    *DS* Give Inventory ALL 2 All by Daemonika Nightfire
    
    Dieses Script gibt "jedem", der das Object klickt, den kompletten Inhalt, mit ausnahme des Scripts aus.
    Anders als bei den aelteren Scripten, wo der Inhalt bei jedem klicken neu ausgelesen wird,
    speichert dieses Script die Namen des Inhalts bereits im State_entry in eine Liste.
*/

list inventory = [];
string name;
integer num;

default
{
    state_entry()
    {
        num = llGetInventoryNumber(INVENTORY_ALL);
        integer     i;
        // ab hier wird das komplette Inventar des Objects ausgelesen
        for(i = 0; i < num; ++i)
        {
            // liesst die Inventar-Namen aus
            name = llGetInventoryName(INVENTORY_ALL, i);
            // Diese Funktion, sorgt dafuer, das das Script nicht zur Liste hinzu gefuegt wird
            if(name != llGetScriptName())
            {
                // fuegt die ausgelesenen Inventar-Namen in die Liste ein.
                inventory += name;
            }
        }
    }
    
    touch_start(integer total_number)
    {
        if(llGetListLength(inventory) < 1)
        {
            // bloed wenn die Box leer ist ;)
            llWhisper(0,"No items to offer.");
        }
        else
        {
            // gibt den gelisteten Inhalt aus (es dauert 3 secunden, bis das Script hier nach wieder reagiert)
            llGiveInventoryList(llDetectedKey(0), llGetObjectName(), inventory);
        }
    }
    
    changed(integer change)
    {
        if(change & CHANGED_INVENTORY)
        {
            // resettet das Script, sobald sich der Inhalt des Objects aendert
            llResetScript();
        }
    }
    
    on_rez(integer Dae)
    {
        // resettet das Script, sobald es gerezzt wird
        llResetScript();
    }
}

Advanced Giver Comparison

Viele Wege fuehren nach Rom, so auch hier. Es gibt mehrere Varianten das Inventar eines Objects auszulesen und in eine Liste zu speichern. Drum moechte ich hier mal 2 Vergleichen.

Version A Version B
    state_entry()
    {
        num = llGetInventoryNumber(INVENTORY_ALL);
        integer     i;
        for(i = 0; i < num; ++i)
        {
            name = llGetInventoryName(INVENTORY_ALL, i);
            if(name != llGetScriptName())
            {
                inventory += name;
            }
        }
    }
    state_entry()
    {
        num = llGetInventoryNumber(INVENTORY_ALL);
        integer     i;
        for(i = 0; i < num; ++i)
        {
            name = llGetInventoryName(INVENTORY_ALL, i);
            inventory += name;
        }
        // Ende der for Schleife / nochmaliges auslesen der Liste
        i = llListFindList(inventory, [llGetScriptName()]);
        inventory = llDeleteSubList(inventory, i, i);
    }
Version A
In der Version A wird das ganze Inventar ausgelesen und die jeweiligen Namen in eine Liste gespeichert.
Allerdings wird das Script in der for Schleife uebergangen und nicht mit aufgelistet.
Version B
In der Version B passiert das gleiche, jedoch wird hier das Script zuerst mit aufgelistet.
Erst nachdem die for Schleife beendet wurde, wird das Script wieder aus der liste entfernt.
Das heisst, hier wird anschliessend die ganze Liste noch einmal ausgelesen um einen einzigen Eintrag zu finden.
Fazit: Nicht empfehlenswert, wenn man auf Memory angewiesen ist.

Unpacker

Folgendes Script ist eigentlich das gleiche wie oben, nur mit dem Unterschied, dass der Owner-Key als globale Variable gespeichert und beim touch gegen geprueft und im changed Event nicht resettet wird, wenn sich etwas am Inventar veraendert.

/*
    *DS* Give Inventory ALL 2 Owner by Daemonika Nightfire
    
    Dieses Script gibt bei klick nur dem Besitzer den kompletten Inhalt, mit ausnahme des Scripts aus.
    Anders als bei den aelteren Scripten, wo der Inhalt bei jedem klicken neu ausgelesen wird,
    speichert dieses Script die Namen des Inhalts bereits im State_entry in eine Liste.
*/


key owner;

list inventory = [];
string name;
integer num;

default
{
    state_entry()
    {
        // Speichert den Besitzer-Key (UUID)
        owner = llGetOwner();
        
        num = llGetInventoryNumber(INVENTORY_ALL);
        integer     i;
        // ab hier wird das komplette Inventar des Objects ausgelesen
        for(i = 0; i < num; ++i)
        {
            // liesst die Inventar-Namen aus
            name = llGetInventoryName(INVENTORY_ALL, i);
            // Diese Funktion, sorgt dafuer, das das Script nicht zur Liste hinzu gefuegt wird
            if(name != llGetScriptName())
            {
                // fuegt die ausgelesenen Inventar-Namen in die Liste ein.
                inventory += name;
            }
        }
    }
    
    touch_start(integer total_number)
    {
        // reagiert nur, wenn der Besitzer klickt
        if(llDetectedKey(0) == owner)
        {
            if(llGetListLength(inventory) < 1)
            {
                // bloed wenn die Box leer ist ;)
                llWhisper(0,"No items to offer.");
            }
            else
            {
                // gibt den gelisteten Inhalt aus (es dauert 3 secunden, bis das Script hier nach wieder reagiert)
                llGiveInventoryList(owner, llGetObjectName(), inventory);
            }
        }
    }
    
    changed(integer change)
    {
        // Hinweis:
        // CHANGED_OWNER wird nicht ausgeloest bei Objecten die im Inventar uebergeben werden.
        if(change & CHANGED_OWNER)
        {
            // resettet das Script, sobald das Object den Besitzer wechselt
            llResetScript();
        }
        
        // Ein Reset bei CHANGED_INVENTORY ist in Verbindung mit (no copy) Items nicht zu empfehlen.
        //if(change & CHANGED_INVENTORY)
        //{
            // resettet das Script, sobald sich der Inhalt des Objects aendert
            //llResetScript();
        //}
    }
    
    on_rez(integer Dae)
    {
        // resettet das Script, sobald es auf dem Boden gerezzt wird
        llResetScript();
    }
}