Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Discussion: Enhanced Single-Item, Single-Prim Item Vendor

Mark Assia
'Eeeeeeeey.
Join date: 10 Jul 2005
Posts: 26
08-02-2006 02:55
This is my first submission to the library, so I might as well make it a useful one. Earlier today I was building a new storefront and wondered how cool it'd be to have the vendors in my storefront interact (sort-of) with my SLExchange listings for all of my items. So, I tossed my clunky JEVN vendor aside and sat down for an hour in front of Wednesday Grimm's Single Item vendor script.

After an hour of recoding and tweaking, I couldn't be happier to release my finished script for free to the masses.

It's pretty well documented, at least in the parts that you should edit. Here's somewhat of a flowchart of what it does:

1. First thing's first - Variable-modifying in the state_entry.
-Checks to see if the string "gItemURL" is defined as an actual URL.
-If not, it disregards all llLoadURL and listen functionality. (Disabling the listen helps to reduce lag)
-If so, it checks the settings and determines which link it's pointing to by reading the domain name. Supported marketplaces at this time are SLExchange, SLBoutique and Gigas.
-After determining the destination, it selects the proper verbal cue for loading the listing URL. It then modifies the second item summary to inform the customer of the verbal cue.

3. On touch, it checks to see if there's a domain name present.
-If so, the object will place the item info in a dialog box and present that to the customer, along with the option to load the URL.
-If not, the object will M the detected avatar with the two summary lines.

4. On request (via dialog), the object will perform llLoadURL.

5. Upon payment, the object will check the item's price. It will determine whether the paid amount is higher, lower or correct. This is practically impossible as Fast Pay is the only payment option. I've left the lower and higher functions in there just in case there's some sort of Fast Pay loophole that a customer unknowingly found.
-If correct, delivery proceeds normally. The object will IM the buyer and thank them using their first name.
-If lower, the object will refund the money and notify the buyer of the low payment and how short they are of the total price.
-If higher, delivery will continue as if the payment was correct, and the correct change will be refunded.

Without further adieu... ;)
EDIT: The updated Sans-Sensor version... :)
CODE

//Adapted from an original Single Item, One Prim Vendor script written by Wednesday Grimm. Modifications and new features added by Mark Assia.
//Not for resale unless adapted to a commercial product and adequate changes to this script have been made.
integer gPrice = 50; // EDIT THIS! Cost of the item
string gItemURL = "http://www.slexchange.com/modules.php?name=Marketplace&file=item&ItemID=21411"; //EDIT THIS! The URL of your item's listing. Leaving this as "" will disable all Marketplace functions in this vendor. Make sure you include the full "http://www." before the domain name! Putting just "slexchange.com", for example, will confuse the vendor!

string itemName = "Generic Widget v1.0";
string summary1 = "Spiff up your whatchamacallit with this doohickey!";
string summary2 = "L$50";
//Don't touch anything below this unless you know what you're doing!
key agentkey;
string gMktplc;
string gAgentname;
integer CHANNEL;
list MENU_MAIN = ["Load URL"];
dispense(key toWhom)
{
llGiveInventory(toWhom, itemName);
}

default
{
state_entry()
{
CHANNEL = (integer)llFrand(-2147483648);
llListen(CHANNEL, "", "", "");
llSetPayPrice(gPrice, [gPrice]);
llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
if (gItemURL != "")
{
if (llGetSubString(gItemURL, 0, 25) == "http://www.slexchange.com/")
gMktplc = "SL Exchange";
else if (llGetSubString(gItemURL, 0, 25) == "http://www.slboutique.com/")
gMktplc = "SL Boutique";
else if (llGetSubString(gItemURL, 0, 27) == "http://www.secondserver.net/")
gMktplc = "Gigas/SecondServer";
}
}
touch_end(integer total_number)
{
key id = llDetectedKey(0);
if (gItemURL != "")
{
llDialog(id, itemName + "\n\n" + summary1 + "\n\n" + summary2 + "\n\nL$" + (string)gPrice, MENU_MAIN, CHANNEL);
}
else
{
llInstantMessage(id, summary1);
llInstantMessage(id, summary2);
}
}
listen(integer channel, string name, key id, string message)
{
if (message == "Load URL")
llLoadURL(id, "You have requested to load a listing from " + gMktplc + ". Continue?", gItemURL);
}


money(key id, integer amt)
{
string firstname = llDeleteSubString(llKey2Name(id), llSubStringIndex(llKey2Name(id), " "), -1);
if (amt == gPrice)
{
dispense(id);
llInstantMessage(id, "Thank you for your purchase, " + firstname + "!");
}
else if (amt < gPrice)
{
integer short = gPrice - amt;
llGiveMoney(id, amt);
llInstantMessage(id, "Sorry, you have not paid the full total of this purchase. You are short of the sale price by L$" + (string)short + ".");
}
else
{
integer change = amt - gPrice;
dispense(id);
llInstantMessage(id, "You have overpaid. I will dispense your change now. Thank you for your purchase, " + firstname + "!");
llGiveMoney(id, change);
}
}
}
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Original Thread
08-02-2006 22:59
/15/28/126305/1.html
_____________________
i've got nothing. ;)
Moopf Murray
Moopfmerising
Join date: 7 Jan 2004
Posts: 2,448
08-03-2006 00:19
Erm.....you might want to check your money event as I can't see a condition that's used if the person pays more than the price of the product. It looks like they won't even get the product as it currently stands.

Also, it might be an idea to use llSetPayPrice to make the pay dialog easier to use.

And I'm sorry but using a sensor in this isn't good practice - I can't understand why you don't just use llInstantMessage regardless so avoiding any chat spam and removing the need for a sensor. Just imagine if people setup 20, 30, 40+ of these in their store, each one running a sensor repeat on a 1 second timer! That's not good for the sim and should be discouraged. And that's even without adding in the open, channel 0 listens that this vendor might use if you've setup an item URL.

PS. Just noticed that your llSensorRepeat call is incorrect, specifically the arc parameter - this should be in radians so for 360 degrees, use the constant TWO_PI
_____________________
Eloise Pasteur
Curious Individual
Join date: 14 Jul 2004
Posts: 1,952
08-03-2006 02:48
Since you're firing the "are they in range" from a touch_end event you don't need sensor at all - the touch_* events are one of the ones that fire the llDetected* functions, so you can just use something along the lines of

if(llVecDist(llGetPos(), llDetectedPos(0)) <10) ... then say your message.

Most of the rest of Moopf's comments too. However, and however counterintuitive it may be, uisng PI in a sensor call for the arc will sweep the whole sphere.
_____________________
Eloise's MiniMall
Visit Eloise's Minimall
New, smaller footprint, same great materials.

Check out the new blog
Frans Charming
You only need one Frans
Join date: 28 Jan 2005
Posts: 1,847
08-03-2006 07:24
From: someone

5. Upon payment, the object will check the item's price. It will determine whether the paid amount is higher, lower or correct. This is practically impossible as Fast Pay is the only payment option. I've left the lower and higher functions in there just in case there's some sort of Fast Pay loophole that a customer unknowingly found.

Good that you did this, but a loophole is not the only reason. The entire userinterface will be opened up at some point and their will be some that override/alter the Fast Pay window. Also now with the development of LibSecondLife in full speed, i expect at some point that we will be able to pay a object through a non graphical interface.

In other words, never ever trust the client.
_____________________
Moopf Murray
Moopfmerising
Join date: 7 Jan 2004
Posts: 2,448
08-03-2006 07:41
Cool, I notice that you've now updated the script to take into account what's been said :)

One other thing that you should probably do is to only activate the listen if the gItemURL field is filled in, that way you're only using resources if they're needed. If it isn't filled in then the functionality that requires the listen isn't even needed.

(You could also go further and start the listen when the user touches the screen and stop it after a minute or so, so you don't always have a listen running at all - you'll then only have a listen running for short times when somebody's interacting with the vendor)

PS> Stopping a listen will require you to set an integer to the return value from llListen, for instance integer listenID = llListen(....) and then you'd call llListenRemove(listenID) to stop the listen.
_____________________