One Item Per Avatar

This script was tested and works on OpenSim version 0.7.4!

giveroneperav.lsl
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//                             CONFIGURATION                             //
///////////////////////////////////////////////////////////////////////////
//                                                                       //
 
// The possible values for this parameter are:
// 0 for textures.
// 1 for sound.
// 3 for landmarks.
// 5 for clothing.
// 6 for objects.
// 7 for notecards.
// 10 for scripts (the giver script will be excluded).
// 13 for body parts.
// 20 for animations.
// 21 for gestures.
 
// The type is 6, so using the reference above, this 
// script will hand out objects.
integer GIVE_TYPE = 7;
 
//                                                                       //
//                             END CONFIGURATION                         //
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
integer wasMenuIndex = 0;
list wasDialogMenu(list input, list actions, string direction) {
    integer cut = 11-wasListCountExclude(actions, [""]);
    if(direction == ">" &&  (wasMenuIndex+1)*cut+wasMenuIndex+1 < llGetListLength(input)) {
        ++wasMenuIndex;
        jump slice;
    }
    if(direction == "<" && wasMenuIndex-1 >= 0) {
        --wasMenuIndex;
        jump slice;
    }
@slice;
    integer multiple = wasMenuIndex*cut;
    input = llList2List(input, multiple+wasMenuIndex, multiple+cut+wasMenuIndex);
    input = wasListMerge(input, actions, "");
    return input;
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
integer wasListCountExclude(list input, list exclude) {
    if(llGetListLength(input) == 0) return 0;
    if(llListFindList(exclude, (list)llList2String(input, 0)) == -1) 
        return 1 + wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
    return wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
list wasListMerge(list l, list m, string merge) {
    if(llGetListLength(l) == 0 && llGetListLength(m) == 0) return [];
    string a = llList2String(m, 0);
    if(a != merge) return [ a ] + wasListMerge(l, llDeleteSubList(m, 0, 0), merge);
    return [ llList2String(l, 0) ] + wasListMerge(llDeleteSubList(l, 0, 0), llDeleteSubList(m, 0, 0), merge);
}
 
integer comHandle = 0;
list storage = [];
list avatars = [];
 
default
{
    state_entry() {
        llSetTimerEvent(1);
        integer i = llGetInventoryNumber(GIVE_TYPE)-1;
        do {
            string name = llGetInventoryName(GIVE_TYPE, i);
            if(name) {
                if(name == llGetScriptName()) jump continue;
                storage += llGetSubString(llGetInventoryName(GIVE_TYPE, i), 0, 23);
            }
@continue;
        } while(--i>-1);
        integer store = llGetListLength(storage);
        if(llGetListLength(storage) == 0) {
            llOwnerSay("There are no items to hand out.");
            state stop;
        }
    }
 
    listen(integer channel, string name, key id, string message) {
        if(message == "⟵ Back") {
            llDialog(id, "\n                      Welcome to the Giver.\nCreated in 2011 by Wizardry and Steamworks\n                 2 August 2011: Version: 1.0\n", wasDialogMenu(storage, ["⟵ Back", "", "Next ⟶"], "<"), channel);
            return;
        }
        if(message == "Next ⟶") {
            llDialog(id, "\n                      Welcome to the Giver.\nCreated in 2011 by Wizardry and Steamworks\n                 2 August 2011: Version: 1.0\n", wasDialogMenu(storage, ["⟵ Back", "", "Next ⟶"], ">"), channel);
            return;
        }
        llListenRemove(comHandle);
        integer i = llGetInventoryNumber(GIVE_TYPE)-1;
        do {
            if(llGetSubString(message, 0, 23) != llGetInventoryName(GIVE_TYPE, i)) jump continue;
            llGiveInventory(id, llGetInventoryName(GIVE_TYPE, i));
            return;
@continue;
 
        } while(--i>-1);
    }
 
    touch_start(integer total_number) {
        key av = llDetectedKey(0);
        if(llListFindList(avatars, (list)av) != -1) {
            llInstantMessage(av, "You already have received an item."); 
            return;
        }
        avatars += av;
        integer comChannel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6));
        comHandle = llListen(comChannel, llDetectedName(0), av, "");
        llDialog(av, "\n                      Welcome to the Giver.\nCreated in 2011 by Wizardry and Steamworks\n                 2 August 2011: Version: 1.0\n", wasDialogMenu(storage, ["⟵ Back", "", "Next ⟶"], ""), comChannel);
    }
 
    timer() {
        // cull the list of avatars if memory is running low
        if(llGetFreeMemory() > 2048) return;
        state stop;
    }
 
    on_rez(integer num) { llResetScript(); }
 
    changed(integer change) { if (change & CHANGED_INVENTORY) llResetScript(); }
}
 
state stop {
    touch_start(integer num) { llResetScript(); }
 
    changed(integer change) { if (change & CHANGED_INVENTORY) llResetScript(); }
 
    on_rez(integer num) { llResetScript(); }
}

This is not SIM crash or restart resistant. For a permanent solution where you store the avatars that used the object, you will need some external data storage.