Pay to Strip

From Second Life Wiki
Jump to: navigation, search

Created by Kira Komarov.

ChangeLog

  • 04-December-2011

Reset on rez, cleaning owner.

  • 23-November-2011

Fixed an off-by-one error between the attachment and attachment prices list.

About

Based on the Tipjar and the Quick Collar, I have thought up a new way of ... dancing, yourself (I would have called it the StripJar, but I thought that might be going too far - ha!). The idea started originally from a joke that everything in Second Life is for sale. So, I thought that perhaps if you are a dancer, you can break yourself up into little pieces: every single attachment or clothes part that you wear will have a price that can be requested when somebody tries to take it off.

The script works like a tip jar: you place it somewhere close to you and people may click it in order to get a menu of available items, as well as a list of prices for that item. When the person wanting to strip you, pays that price, then using RLV, that clothes piece they selected, will be automatically removed.

Features

  • Every single clothes piece or attachment can be configured to have a price. Ask you local "friend-in-friends-list-into-bsdm-we-keep-around-just-in-case-we-become-so-inclined" how to do that with the viewer you are using.
  • You may exclude any clothes type or attachment point.

Requirements

  • The script requires a RLV viewer with RLV turned on.
  • Entrepreneurship.

Limitations

Yes, it would be cool if we could attach the object instead of having to rez it in-world. However, LSL doctrine dictates:

Money cannot be paid to an attachment.

Setup

  • Create a box and drop the script below inside it.
  • Adjust the price for both clothes and attachments as indicated in the configuration section of the script.
  • Save the script and you are ready to go.

Code

//////////////////////////////////////////////////////////
// [K] Kira Komarov - 2011, License: GPLv3              //
// Please see: http://www.gnu.org/licenses/gpl.html     //
// for legal details, rights of fair usage and          //
// the disclaimer and warranty conditions.              //
//////////////////////////////////////////////////////////
 
//////////////////////////////////////////////////////////
//                   CONFIGURATION                      //
//////////////////////////////////////////////////////////
// If there is any attachment point you do not want to 
// let people strip, replace the name with a star. For
// example, to prevent people stripping your hair, and
// provided that you hair is attached to your skull, you
// would replace in the list below "skull" with "*"
list ATTACHMENTS = [ "*", "chest", "skull", "left shoulder", "right shoulder", "left hand", "right hand", "left foot", "right foot", "spine", "pelvis", "mouth", "chin", "left ear", "right ear", "left eyeball", "right eyeball", "nose", "r upper arm", "r forearm", "l upper arm", "l forearm", "right hip", "r upper leg", "r lower leg", "left hip", "l upper leg", "l lower leg", "stomach", "left pec", "right pec", "center 2", "top right", "top", "top left", "center", "bottom left", "bottom", "bottom right" ];
// These are the prices required to strip every single
// attachment point. Everything you wear is dynamically 
// assessed once the script kickstarts. You do not need 
// to remove anything. Instead, replace 10 by the amount 
// of L$ you want people to pay you to strip that certain 
// item. This list is exactly sorted like the previous one
// so "chest" is the first "10", for example.
list ATTACHMENTS_PRICES = [ "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10" ];
// The same like attachment, these are the clothes list 
// replace anything you do not want with a zero. For example
// to prevent people stripping your "underpants", replace 
// "underpants" with "0".
list CLOTHES = [ "gloves", "jacket", "pants", "shirt", "shoes", "skirt", "socks", "underpants", "undershirt" ];
list CLOTHES_PRICES = [ "10", "10", "10", "10", "10", "10", "10", "10", "10" ];
// This is how much time in seconds you allow people to 
// pay the amount, till they get a timeout message and 
// the script kickstarts again.
integer PAY_TIMEOUT = 30;
//////////////////////////////////////////////////////////
//                  END CONFIGURATION                   //
//////////////////////////////////////////////////////////
 
list menu_items = [];
list key_items = [];
integer mitra = 0;
integer comChannel = 0;
integer comHandle = 0;
integer tmpHandle = 0;
list cList = [];
integer RFO = 0;
 
key stripRequestAVKey = NULL_KEY;
string stripRequestItem = "";
integer stripRequestType = 0;
integer stripRequestPrice = 0;
 
list mFwd() {
    if(mitra+1>llGetListLength(menu_items)) return cList;
    cList = llListInsertList(llListInsertList(llList2List(menu_items, ++mitra, (mitra+=9)), ["<= Back"], 0), ["Next =>"], 2);
    return cList;
} 
 
list mBwd() {
    if(mitra-19<0) return cList;
    cList = llListInsertList(llListInsertList(llList2List(menu_items, (mitra-=19), (mitra+=9)), ["<= Back"], 0), ["Next =>"], 2);
    return cList;
}
cNegotiate() {
            if(stripRequestType == 1) {
                stripRequestPrice = llList2Integer(CLOTHES_PRICES, llListFindList(CLOTHES, (list)stripRequestItem));
                llInstantMessage(stripRequestAVKey, "The price for that item is: " + (string)stripRequestPrice + " please right click this object and select pay.");
                jump wait;
            }
            stripRequestPrice = llList2Integer(ATTACHMENTS_PRICES, llListFindList(ATTACHMENTS, (list)stripRequestItem)) ;
            llInstantMessage(stripRequestAVKey, "The price for that item is: " + (string)stripRequestPrice + " please right click this object and select pay.");
@wait;
            llSetPayPrice(stripRequestPrice, [ stripRequestPrice, 0, 0, 0]);
            llSetTimerEvent(PAY_TIMEOUT);
}
default
{
    state_entry()
    {
        llSetText("Please wait... ", <1,1,1>, 1.0);
        comHandle = llListen(69, "", llGetOwner(), "");
        llSetTimerEvent(1);
        llOwnerSay("@version=69");
    }
 
    on_rez(integer param) {
        llResetScript();
    }
 
    timer() {
        if(RFO == 1) {
            llSetText("Touch to strip " + llKey2Name(llGetOwner()), <1,1,1>, 1.0);
            llSetTimerEvent(0);
            return;
        }
    }
 
    run_time_permissions(integer perm) {
        if(perm & PERMISSION_DEBIT)
            RFO = 1;
    }
 
    listen( integer channel, string name, key id, string message ) {
 
        if(channel == 69 ) {
            llListenRemove(comHandle);
            comHandle = llListen(70, "", llGetOwner(), "");
            llOwnerSay("@getoutfit=" + (string)70);
            return;
        }
        if(channel == 70) {
            llListenRemove(comHandle);
            integer itra;
            list vCLOTHES = [];
            list vCLOTHES_PRICES = [];
            for(itra=0; itra<llStringLength(message); ++itra) {
                if(llGetSubString(message, itra, itra) == "1" && llStringLength(llList2String(CLOTHES, itra)) > 1) {
                    vCLOTHES += llList2String(CLOTHES, itra);
                    vCLOTHES_PRICES += llList2String(CLOTHES_PRICES, itra);
                }
            }
            CLOTHES=vCLOTHES;
            CLOTHES_PRICES=vCLOTHES_PRICES;
            comHandle = llListen(71, "", llGetOwner(), "");
            llOwnerSay("@getattach=" + (string)71);
            return;
        }
        if(channel == 71) {
            llListenRemove(comHandle);
            integer itra;
            list vATTACHMENTS = [];
            list vATTACHMENTS_PRICES = [];
            for(itra=0; itra<llStringLength(message); ++itra) {
                if(llGetSubString(message, itra, itra) == "1" && llStringLength(llList2String(ATTACHMENTS, itra)) > 1) {
                    vATTACHMENTS += llList2String(ATTACHMENTS, itra);
                    vATTACHMENTS_PRICES += llList2String(ATTACHMENTS_PRICES, itra);
                }
            }
            ATTACHMENTS = vATTACHMENTS;
            ATTACHMENTS_PRICES = vATTACHMENTS_PRICES;
            if(!(llGetPermissions() & PERMISSION_DEBIT)) llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);  
            return;
        }
 
        if(channel == comChannel + 1 && message != "Next =>" && message != "<= Back") {
            llListenRemove(tmpHandle);
            stripRequestAVKey = id;
            stripRequestItem = message;
            stripRequestType = 1;
            state strip;
        }
        if(channel == comChannel +2 && message != "Next =>" && message != "<= Back") {
            llListenRemove(tmpHandle);
            stripRequestAVKey = id;
            stripRequestItem = message;
            stripRequestType = 2;
            state strip;
        }
 
        if(message == "Wearables") {
            integer itra;
            for(itra=0, menu_items=[], mitra=0; itra<llGetListLength(CLOTHES); ++itra) {
                menu_items += llList2String(CLOTHES, itra);
            }
            cList = llListInsertList(llListInsertList(llList2List(menu_items, mitra, (mitra+=9)), ["<= Back"], 0), ["Next =>"], 2);
            llListenRemove(tmpHandle);
            tmpHandle = llListen(comChannel+1, "", id, "");
            llDialog(id, "Please select the clothes to detach:\n", cList, comChannel+1);
        }
 
        if(message == "Attachments") {
            integer itra;
            for(itra=0, menu_items=[], mitra=0; itra<llGetListLength(ATTACHMENTS); ++itra) {
                menu_items += llList2String(ATTACHMENTS, itra);
            }
            cList = llListInsertList(llListInsertList(llList2List(menu_items, mitra, (mitra+=9)), ["<= Back"], 0), ["Next =>"], 2);
            llListenRemove(tmpHandle);
            tmpHandle = llListen(comChannel+2, "", id, "");
            llDialog(id, "Please select the attachments to detach:\n", cList, comChannel+2);
        }
 
        if(message == "Strip" ) {
            llDialog(id, "Please select the type of clothing to remove:\n", ["Wearables", "Attachments"], comChannel);
            return;
        }
 
        if(message == "<= Back") {
            llDialog(id, "Please browse the available items:\n", mBwd(), channel);
            return;
        }
 
        if(message == "Next =>") {
            llDialog(id, "Please browse the available items:\n", mFwd(), channel);
            return;
        }
        llListenRemove(comHandle);
    }
 
    touch_start(integer total_number)
    {
        comChannel = ((integer)("0x"+llGetSubString((string)llGetKey(),-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF;
        comHandle = llListen(comChannel, llDetectedName(0), llDetectedKey(0), "");
        llDialog(llDetectedKey(0), "You may strip clothes off me by selecting an item and then paying the price that will be sent to you.", ["Strip"], comChannel);
    }
}
 
state strip {
 
    state_entry() {
        llSetText(llKey2Name(llGetOwner()) + " is being stripped... Please wait....", <1,1,1>, 1.0);
        if(!(llGetPermissions() & PERMISSION_DEBIT)) {
            llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
            return;
        }
        cNegotiate();
    }
 
    run_time_permissions(integer perm)
    {
        if (perm & PERMISSION_DEBIT)
        {
            cNegotiate();
        }
    }
 
    timer() {
        llInstantMessage(stripRequestAVKey, "I'm sorry, the request to strip me timed out. Please touch me again.");
        llSetTimerEvent(0);
        state default;
    }
 
    money(key id, integer amount) {
        if(amount != stripRequestPrice) {
            llInstantMessage(stripRequestAVKey, "Sorry, that is not the correct price for that item.");
            llGiveMoney(stripRequestAVKey, amount);
            state default;
            return;
        }
        if(stripRequestType == 1) {
            llOwnerSay("@remoutfit:" + stripRequestItem + "=force");
            state default;
            return;
        }
        llOwnerSay("@detach:" + stripRequestItem + "=force");
        state default;
    }
 
}

Hacks and Developments

  • It could be altered and expanded so it would not require it to be owned by the user. That way it would work in a club - although it might complicate matters because my headphones, as a vague example, are much more expensive to remove than anybody else's. In that case, it's back to hotswap notecards.
  • It could be expanded and coupled with a regular Tipjar. The only problem would be collisions between money() events when both the Tipjar script and this one (the Stripjar script) will be ready for cash. That can only happen if, say a user (pervert) selected something to strip off you and another user tips an amount. I guess some sort of synchronization between the two scripts would be necessary to prevent that (llMessageLinked() & Co.). Another option, would just be not to return the money. In that case, it's either a tip or a striptip, yet, that shallen't matter. Shall it?
  • It could be made more user-friendly by making it more verbose; ie: adding hooks for more llSetText() messages, IMing info about what's currently happening, etc...
  • And for Godssake, somebody change those *_PRICES lists to contain integers instead of strings.
  • ... while you're at it, find a way to declare and allocate them inline in order to reduce standby memory.