Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Szentasha's custom Hiro 1-prim vendor script

Szentasha Salome
Registered User
Join date: 10 May 2005
Posts: 20
09-13-2005 09:55
I would like to thank Hiro for making his vendor scripts public! I had some special needs and was excited to be able to make changes to the script to make my vendors work the way I wanted. I'll be posting the custom script here. I'm sure there will be those that like and don't like these changes. I tested some but can't guarentee there are not errors, and accept no responsibility for your use or continued modification of this script.

Please let me know if you find any problems. Thanks again Hiro!

There are lots of changes, but the main things I wanted to change were having the vendor name determined by the object name, and to have a way to turn off listening to reduce lag. Some mall owners are very touchy about vendors that cause script lag.

Changes are as follows.

1. Modified a number of command names to make them shorter and easier to remember
- GetHiroVendorName -> getname
- updateitems -> update
- listitems -> list
- clearsales -> clear
- setprice ->price

2. Vendor name is now determined by object name
- the name is the characters of the object name up to a space
- for example, if the object name is "soft pillow (mirage)", the vendor name will be "soft"

3. All listening vendors can be commanded using the name 'all'
- for example, "all:update"

4. All new vendors can be commanded using the name 'new'
- for example, "new:update"
- vendors are considered new until update is called

5. If the owner touches the vendor, listening mode will be toggled
- default is listening
- message will display "Listening to commands" or "Deaf to commands"
- when a vendor is deaf it will not respond to commands and will not cause script lag

6. Added command: deaf
- turns off listening
- for example, "all:deaf"

7. Added command: touch
- causes the vendor to act like it was touched by someone who isn't the owner
- can be used to test the vendor since owner touch has new meaning

8. Added command: sumsales
- displays the total number of sales and the total number of lindens made from recent sales (does not list individual sales)

9. Added an optional parameter to update for setting the price
- if a price is added to the end of update, it will update the contents and set the price if there is only one item
- for example: "soft:update:50"
- this acts the same as "soft:update" followed by "soft:price:all:50"
Szentasha Salome
Registered User
Join date: 10 May 2005
Posts: 20
09-14-2005 16:37
CODE
// Header:
// (c) 2004 Original Super Vendor Script by the player Hiro Pendragon for Second Life (tm).
// This code is meant to be open source and free and is NOT to be resold in unmodified or modified form.
// Any modifications made to this script should be listed here in the header.
// This header is NOT to be modified in any way other than adding additional comments.
// Violation of these rules is considered consent to immediately turn over all rights and profits
// made using this script to the original player of Hiro Pendragon.
//
// Hiro Pendragon guarantees NO assistance or technical support with this script.
//
// Dev notes:
// Yeah, I know the original script doesn't have procedues pulled out into seperate functions
// as they could be. This evolved as a quick script for my own use, and because the size was
// relatively small, I decided to not spend the time going through and pulling out functions.
// Good luck, I hope you folks using this code can help innovate Second Life! -Hiro Pendragon
//
//
// End of Header //

// Modifications by Szentasha:
//
// Commands can start with 'all' to target all vendors
// Commands starting with 'new' will target vendors that haven't been updated yet
// Command to get name: getname
// Changed updateitems to: update
// Changed listitems to: list
// Changed clearsales to: clear
// Changed setprice to: price
// Vendorname is now the object name before spaces. So "sv09 (store)" is vendor name "sv09"
// Added command: sumsales: this command gives total linden from all sales, not each sale
// You can add a price parameter to update that will set the item price if there is only one item. For example: all:update:50
// If the owner touches the vendor, it will stop listening to commands. Touch again to continue listening.
// Added command: touch: can be used by the owner to test since touching turns listening off
// Added command: deaf: turns off listening. usefull because you can do: all:deaf


key ownerkey; // used to check command authorization

string vendorname = "vendor";
integer newvendor = 1;
// this string proceeds all commands, so you can use multiple vendors in one area and
// specificy which one you want to talk to by using different names for each

list currentitemlist; // stores the list of items for sale
list currentpricelist; // stores the list of prices
list recentsales; // list of sales information

integer defaultprice=9999999;
// init to 10 million to prevent accidental setup and people purchasing stuff for 0L


integer numberitems = 0; // number of items set to the currentitemlist
integer selected = 1;
// which item in the list is selected in the vendor, from 1 to numberitems

integer recordsales = 1; // 1 = records the sales, 0 = record sale mode off

integer percentshare = 0; // stores the percentage shared 0-100
integer owed = 0; // stores the amount of L$ owed a partner

integer storelisten = 0; // used for listens

// constants
float r=1.0;
float g=1.0;
float b=1.0;



updatetext()
// called at any time after updateitems is called, updates the floating text on the vendor
{
if(r==-1)
llSetText("",<0,0,0>,100); // if r set to -1, hide text
else //
llSetText(llList2String(currentitemlist,(selected - 1))+
"\n$"+llList2String(currentpricelist,(selected - 1))+"L"
+"\nItem "+(string)selected+" of "+(string)numberitems,
<r,g,b>, 1.5);

}


listsaleitems()
// outputs to channel 0 all items for sale & prices
{
integer c = llGetListLength(currentitemlist);
llSay(0,"There are currently "+(string)c+" items for sale in vendor "+vendorname+".");
integer d;
for(d = 0;d<c;++d)
{
llSay(0,"Item "+((string)(d+1))+":"+llList2String(currentitemlist,d)+
", price: "+llList2String(currentpricelist,d));
}

}

Init()
{
ownerkey = llGetOwner();
llRequestPermissions(ownerkey,PERMISSION_DEBIT);
}

////////////// DEFAULT / INIT STATE ////////////

default
// If a vendor has not been initialized, do init and go into listenmode
{

state_entry()
{
Init();
state listenmode;
}

on_rez(integer param)
{
Init();
state listenmode;
}
}

///////// STATE LISTENMODE - MAIN STATE ///////

state listenmode
{
// DEV NOTES: If you'd like, move the listens to a channel other than 0.
state_entry()
{
llListenRemove(storelisten); // removes listen as precaution
storelisten = llListen(0,"",ownerkey,""); // listen only to owner
}

on_rez(integer param)
{
Init();
llListenRemove(storelisten); // removes listen as precaution
storelisten = llListen(0,"",ownerkey,""); // listen only to owner

}

listen(integer channel, string name, key id, string msg)
{
@again;

list command = llParseString2List(msg,[":"],[]); // input parsed into a list by ":"
string target = llList2String(command,0);

list vnlist=llParseString2List(llGetObjectName (),[" "],[]);
vendorname = llList2String(vnlist,0);

if(target==vendorname || target=="all" || (target == "new" && newvendor == 1))
// ALL COMMANDS MUST START WITH THE VENDORNAME
{
string whichcommand=llList2String(command,1); // grab first word in the command

// COMMAND setname
if(whichcommand=="setname")
{
llSay(0,"setname is no longer a supported command. The vendor name is determined by the object name. This vendor's name is "+vendorname);
}

// COMMAND updateitems
else if(whichcommand=="update")
// this section scans through items in the object and puts them in a list
{
newvendor = 0;
integer numitems=0;
numitems += llGetInventoryNumber(INVENTORY_OBJECT);
// all items in the vendor's contents are put for sale

llSay(0,(string)numitems+" items found in this vendor:");
numberitems = numitems;
list itemlist; // temporary list to work on
integer c;
integer listlength=llGetListLength(currentitemlist);
if (listlength > 20)
// I made 20 an arbitrary recommended maximum just for ease of use
{
llSay(0,"Warning! Items for sale exceeds recommended maximum.");
}
currentpricelist = llDeleteSubList(currentpricelist,0,(listlength - 1));
// clear the current list

for(c=0;c<numitems;++c)
// put all objects on the sale list and initialize prices to 10mil
{
itemlist += llGetInventoryName(INVENTORY_OBJECT,c);
llSay(0,((string)(c+1))+":"+llList2String(itemlist,c));
currentpricelist=currentpricelist+(string)defaultprice;
}

currentitemlist=itemlist; // main list is updated
selected = 1; // sets the vendor to the first item
updatetext();

string newprice=llList2String(command,2);
if (newprice!="")
{
msg = vendorname+":price:all:"+newprice;
jump again;
}

llSay(0,"You now need to update all of the prices.");
// reminder to the user

}
else if(whichcommand=="list")
{
listsaleitems();
}
else if(whichcommand=="price")
// setprice has 2 modes - set all, or set one
{
if(llList2String(command,2)=="all")
// if "all" entered, accept a list of new prices
{
list newpricelist=llParseString2List(llList2String(command,3),[","],[]);
// takes the user comma-deliniated input
integer newlength = llGetListLength(newpricelist);
integer oldlength = llGetListLength(currentpricelist);
if(newlength!=oldlength)
// error - wrong number of prices entered
{
llSay(0,"Error! The list of prices you entered ("+((string)newlength)
+") does not have the same number as already exists! ("
+((string)oldlength)+")");
}
else
{
integer c;
integer valid = 1;
for(c=0;c<newlength;++c)
{
integer newprice = (integer)llList2String(newpricelist,c);
if(newprice<0)
// error trap - all prices must be non-negative
{
valid=valid - 1;
}
}
if(valid<1)
{
llSay(0,"Error! "+((string)(1 - valid))+"prices were less than 0.");
}
else
// else all values are > 0, go ahead and change prices
{
llSay(0,"Prices being updated.");
currentpricelist = newpricelist;
updatetext();

}
}
} // end setprice "all" routine


else if(llList2String(command,2)!="")
// set price of just one item
{
integer whichitem = (integer)llList2String(command,2);
if(whichitem>llGetListLength(currentpricelist))
// get the index of the item to change price on, make sure it's < numberitems
{
llSay(0,"Error! Item index is greater than the actual number of items!");
}
else
{
whichitem--;
// since users will input 1 to numberitems, this adjusts to reference the list

integer newprice = (integer)llList2String(command,3);
if(newprice<0)
// error trap for negative prices
{
llSay(0,"Error! Must enter a non-negative price!");
}
else
// else price is valid, need to cut and paste this one into the list
{
integer pricelistlength = llGetListLength(currentpricelist);
integer c;
list newpricelist;
for(c=0;c<pricelistlength;++c)
// creates the new price list and replaces
{
if(c==whichitem)
{
newpricelist = newpricelist + (string)newprice;
}
else
{
newpricelist = newpricelist + llList2String(currentpricelist,c);
}
}
llSay(0,"Prices being updated.");
currentpricelist = newpricelist;
updatetext();
}
}

}
} //end setprice


else if(whichcommand == "setcolor")
// setcolor inputs RGB values for the floating text. values > 1 are 1, values < 0 are 0 in SL
// NOTES: There's no reason input could be changed to 0-255 by simply dividing the float
// by 255 before setting the value of the colors
{
list colors = llParseString2List(llList2String(command,2),[","],[]);
r = (float)(llList2String(colors,0));
g = (float)(llList2String(colors,1));
b = (float)(llList2String(colors,2));
updatetext();
}

else if(whichcommand == "resetscript")
// This was used because the script was no-mod and it gave users a way to reset the script.
// This command can be omitted if distributing with mod permission
{
llResetScript();
}


// Command listsales - lists sales / toggles sales tracker
else if(whichcommand == "listsales")
{
integer howmany = (integer)llList2String(command,2);
integer c;
integer leng = llGetListLength(recentsales);
if (howmany == -1)
// if user input is -1, toggle sales tracking
{
if(recordsales ==1) // if on, turn off
{
llSay(0,"Disabling sales tracking for vendor: "+vendorname);
recordsales = 0;
recentsales = llDeleteSubList(recentsales,0,(llGetListLength( recentsales ) - 1));
}
else // else off, turn on
{
llSay(0,"Re-enabling sales tracking for vendor: "+vendorname);
recordsales = 1;
}
}

else if(recordsales == 1)
// else, if sales tracker mode is on, do list
{
if ((howmany < 1)||(howmany > leng))
howmany = leng;
// default is to show the whole list

llSay(0,"Listing "+(string)howmany+" items that have sold recently:");
for(c=1;c<=howmany;c++)
{
llSay(0,llList2String(recentsales,(leng - c)));
}
}
} // end command listsales
else if(whichcommand == "sumsales")
{
integer howmany = (integer)llList2String(command,2);
integer c;
integer leng = llGetListLength(recentsales);

if(recordsales == 1)
// else, if sales tracker mode is on, do list
{
integer sum = 0;
integer price;
string temp;
list templist;

for(c=0;c<leng;c++)
{
temp = llList2String(recentsales,c);
templist = llParseString2List(temp,[":"],[]);
price = (integer)llList2String(currentpricelist, (integer) llList2String (templist, 1) - 1);
// llSay (0, "Found an item costing " + (string) price);
sum += price;
}

llSay(0,(string)leng+" items that have sold for "+(string) sum);
}
} // end command sumsales
else if (whichcommand == "touch")
{
selected++;
if (selected > numberitems)
selected = selected - numberitems;
llSetTexture(llList2String(currentitemlist, (selected - 1) )+"PIC",ALL_SIDES);
updatetext();
}
else if (whichcommand == "deaf")
{
llListenRemove(storelisten); // removes listen
storelisten = 0;
llSay(0,"Deaf to commands.");
}
else if(whichcommand == "clear")
{
recentsales = llDeleteSubList(recentsales,0,(llGetListLength( recentsales ) - 1));
llSay(0,"Clearing sales list.");
}

else if(whichcommand == "getfreemem")
// get the free memory in the sim... just a handy feature for busy sims
{
llSay(0,(string)llGetFreeMemory());
}

// command share - toggles / changes share settings
// Dev notes: If I had time, I would have added a command that would have allowed a user
// to touch the vendor and grab their key, then alter payment to directly pay shares,
// and also allow multiple sales. -Hiro
else if(whichcommand == "share")
{
string whattodo = llList2String(command,2);
if(whattodo == "set")
// the "set" switch indicates the percentage of share tracking should be set
{
integer newpercent = (integer)llList2String(command,3);
if((newpercent<0)||(newpercent>100))
llSay(0,"Error! Sharing percentage must be 0-100%");
else
{
percentshare = newpercent;
llSay(0,"New percentage shared is "+(string)percentshare);
}
}
else if(whattodo == "show")
// the "show" switch shows the total money owed in the share
{
if(owed>0)
llSay(0,"You currently owe "+(string)owed+"L to whom you are sharing.");
}
else if(whattodo == "clear")
// Dev notes: Yeah, it's ghetto. You have to manually pay your partner and clear by hand.
// I've been too busy to fix it, but now you all can do it yourself! *chuckles* -Hiro
{
llSay(0,"Setting amount owed from "+(string)owed+"L to 0L.");
owed = 0;
}
}

} // end share


else // else the command does not start with the vendorname string
if(llList2String(command,0)=="getname")
// useful command if you've forgotten the name of your vendor
{
llSay(0,"My name is: "+vendorname);
}
} // end listen


link_message( integer sender_num, integer num, string str, key id)
// link message receives back/forward options from the buttons.
// REMARK out this whole section if you're using a 1-prim vendor.
{
// llSay(0,"changing");
if(str=="forward")
{
selected++;
if (selected > numberitems)
selected = selected - numberitems;
llSetTexture(llList2String(currentitemlist, (selected - 1) )+"PIC",ALL_SIDES);
updatetext();

}
if(str=="backward")
{
selected = selected - 1;
if (selected < 1)
selected = selected + numberitems;
llSetTexture(llList2String(currentitemlist, (selected - 1) )+"PIC",ALL_SIDES);
updatetext();
}

} // End link message

touch( integer n)
// touch script optional for vendor with arrows, but required for 1-prim vendor
{
if (llGetOwner () == llDetectedKey (0))
{
if (storelisten == 0)
{
storelisten = llListen(0,"",ownerkey,""); // listen only to owner
llSay(0,"Listening to commands.");
}
else
{
llListenRemove(storelisten); // removes listen
storelisten = 0;
llSay(0,"Deaf to commands.");
}
}
else
{
selected++;
if (selected > numberitems)
selected = selected - numberitems;
llSetTexture(llList2String(currentitemlist, (selected - 1) )+"PIC",ALL_SIDES);
updatetext();
}
}


money( key giver, integer amount )
// Thanks Kaleb Underthor for your shared money function that I borrowed -Hiro
{
integer price = (integer)llList2String(currentpricelist, (selected - 1) );
string object = llList2String(currentitemlist, (selected - 1) );
if ( amount < price )
// if underpayment, return money
{
llSay( 0, "This item costs L$" + (string) price );
llSay( 0, "You only paid "+(string)amount);
llGiveMoney( giver, amount );

}
else
{
llSay( 0, "Enjoy your " + object );
llGiveInventory( giver, object );
if(llGetListLength(recentsales)>=30)
llDeleteSubList(recentsales,0,0);
// sales list limited to 30 so that mall sims don't run out of memory!

if(recordsales==1) // if sales tracking on, record the sales
recentsales = recentsales + (llGetDate()+":"+(string)selected+":"+object+":"+(string)price);
//fixing the error here

if (amount > price)
// if overpayment, give change
{
llGiveMoney(giver, amount - price);
}

if(percentshare > 0) // if share mode on, then add share moneys
{
owed += ((price * percentshare)/100);
}

//
}
} // end money routine
}


edit- added code tags, ne
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Discussion Thread
09-15-2005 06:33
/54/fa/61644/1.html
_____________________
i've got nothing. ;)